Compare commits

..

1 Commits

Author SHA1 Message Date
0e7c55e108 CE-1240: added multi table widget type 2024-05-03 20:29:50 -05:00
16 changed files with 154 additions and 349 deletions

View File

@ -84,7 +84,7 @@ public class MetaDataAction
}
QBackendMetaData backendForTable = metaDataInput.getInstance().getBackendForTable(tableName);
tables.put(tableName, new QFrontendTableMetaData(backendForTable, table, false, false));
tables.put(tableName, new QFrontendTableMetaData(metaDataInput, backendForTable, table, false, false));
treeNodes.put(tableName, new AppTreeNode(table));
}
metaDataOutput.setTables(tables);

View File

@ -54,7 +54,7 @@ public class TableMetaDataAction
throw (new QNotFoundException("Table [" + tableMetaDataInput.getTableName() + "] was not found."));
}
QBackendMetaData backendForTable = tableMetaDataInput.getInstance().getBackendForTable(table.getName());
tableMetaDataOutput.setTable(new QFrontendTableMetaData(backendForTable, table, true, true));
tableMetaDataOutput.setTable(new QFrontendTableMetaData(tableMetaDataInput, backendForTable, table, true, true));
// todo post-customization - can do whatever w/ the result if you want

View File

@ -65,7 +65,7 @@ public class PermissionsHelper
*******************************************************************************/
public static void checkTablePermissionThrowing(AbstractTableActionInput tableActionInput, TablePermissionSubType permissionSubType) throws QPermissionDeniedException
{
checkTablePermissionThrowing(tableActionInput.getTableName(), permissionSubType);
checkTablePermissionThrowing(tableActionInput, tableActionInput.getTableName(), permissionSubType);
}
@ -73,7 +73,7 @@ public class PermissionsHelper
/*******************************************************************************
**
*******************************************************************************/
private static void checkTablePermissionThrowing(String tableName, TablePermissionSubType permissionSubType) throws QPermissionDeniedException
private static void checkTablePermissionThrowing(AbstractActionInput actionInput, String tableName, TablePermissionSubType permissionSubType) throws QPermissionDeniedException
{
warnAboutPermissionSubTypeForTables(permissionSubType);
QTableMetaData table = QContext.getQInstance().getTable(tableName);
@ -99,11 +99,11 @@ public class PermissionsHelper
/*******************************************************************************
**
*******************************************************************************/
public static boolean hasTablePermission(String tableName, TablePermissionSubType permissionSubType)
public static boolean hasTablePermission(AbstractActionInput actionInput, String tableName, TablePermissionSubType permissionSubType)
{
try
{
checkTablePermissionThrowing(tableName, permissionSubType);
checkTablePermissionThrowing(actionInput, tableName, permissionSubType);
return (true);
}
catch(QPermissionDeniedException e)

View File

@ -495,15 +495,15 @@ public class RunProcessAction
String basepullKeyValue = (basepullConfiguration.getKeyValue() != null) ? basepullConfiguration.getKeyValue() : process.getName();
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// if process specifies that it uses variants, look for that data in the session and append to our basepull key //
// if backend specifies that it uses variants, look for that data in the session and append to our basepull key //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(process.getVariantBackend() != null)
if(process.getSchedule() != null && process.getVariantBackend() != null)
{
QSession session = QContext.getQSession();
QBackendMetaData backendMetaData = QContext.getQInstance().getBackend(process.getVariantBackend());
if(session.getBackendVariants() == null || !session.getBackendVariants().containsKey(backendMetaData.getVariantOptionsTableTypeValue()))
{
LOG.warn("Could not find Backend Variant information for Backend '" + backendMetaData.getName() + "'");
LOG.info("Could not find Backend Variant information for Backend '" + backendMetaData.getName() + "'");
}
else
{

View File

@ -914,7 +914,7 @@ public class QInstanceValidator
}
assertCondition(fieldSecurityLock.getDefaultBehavior() != null, prefix + "has a fieldSecurityLock that is missing a defaultBehavior");
assertCondition(CollectionUtils.nullSafeHasContents(fieldSecurityLock.getKeyValueBehaviors()), prefix + "has a fieldSecurityLock that is missing keyValueBehaviors");
assertCondition(CollectionUtils.nullSafeHasContents(fieldSecurityLock.getOverrideValues()), prefix + "has a fieldSecurityLock that is missing overrideValues");
}
for(FieldAdornment adornment : CollectionUtils.nonNullList(field.getAdornments()))

View File

@ -54,6 +54,7 @@ public class CompositeWidgetData extends AbstractBlockWidgetData<CompositeWidget
/////////////////////////////////////////////////////////////
// note, these are used in QQQ FMD CompositeWidgetData.tsx //
/////////////////////////////////////////////////////////////
FLEX_COLUMN,
FLEX_ROW_WRAPPED,
FLEX_ROW_SPACE_BETWEEN,
TABLE_SUB_ROW_DETAILS,

View File

@ -0,0 +1,97 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.model.dashboard.widgets;
import java.util.List;
/*******************************************************************************
** Model containing datastructure expected by frontend bar chart widget
**
*******************************************************************************/
public class MultiTableData extends QWidgetData
{
List<TableData> tableDataList;
/*******************************************************************************
**
*******************************************************************************/
public MultiTableData()
{
}
/*******************************************************************************
**
*******************************************************************************/
public MultiTableData(List<TableData> tableDataList)
{
setTableDataList(tableDataList);
}
/*******************************************************************************
** Getter for type
**
*******************************************************************************/
public String getType()
{
return WidgetType.MULTI_TABLE.getType();
}
/*******************************************************************************
** Getter for tableDataList
*******************************************************************************/
public List<TableData> getTableDataList()
{
return (this.tableDataList);
}
/*******************************************************************************
** Setter for tableDataList
*******************************************************************************/
public void setTableDataList(List<TableData> tableDataList)
{
this.tableDataList = tableDataList;
}
/*******************************************************************************
** Fluent setter for tableDataList
*******************************************************************************/
public MultiTableData withTableDataList(List<TableData> tableDataList)
{
this.tableDataList = tableDataList;
return (this);
}
}

View File

@ -42,6 +42,7 @@ public enum WidgetType
SMALL_LINE_CHART("smallLineChart"),
LOCATION("location"),
MULTI_STATISTICS("multiStatistics"),
MULTI_TABLE("multiTable"),
PIE_CHART("pieChart"),
QUICK_SIGHT_CHART("quickSightChart"),
STATISTICS("statistics"),

View File

@ -35,17 +35,16 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper;
import com.kingsrook.qqq.backend.core.actions.permissions.TablePermissionSubType;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
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.security.FieldSecurityLock;
import com.kingsrook.qqq.backend.core.model.metadata.sharing.ShareableTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.Capability;
import com.kingsrook.qqq.backend.core.model.metadata.tables.ExposedJoin;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QSupplementalTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.session.QSession;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
@ -88,14 +87,12 @@ public class QFrontendTableMetaData
/*******************************************************************************
**
*******************************************************************************/
public QFrontendTableMetaData(QBackendMetaData backendForTable, QTableMetaData tableMetaData, boolean includeFullMetaData, boolean includeJoins)
public QFrontendTableMetaData(AbstractActionInput actionInput, QBackendMetaData backendForTable, QTableMetaData tableMetaData, boolean includeFullMetaData, boolean includeJoins)
{
this.name = tableMetaData.getName();
this.label = tableMetaData.getLabel();
this.isHidden = tableMetaData.getIsHidden();
QSession qSession = QContext.getQSession();
if(includeFullMetaData)
{
this.primaryKeyField = tableMetaData.getPrimaryKeyField();
@ -103,21 +100,7 @@ public class QFrontendTableMetaData
for(String fieldName : tableMetaData.getFields().keySet())
{
QFieldMetaData field = tableMetaData.getField(fieldName);
////////////////////////////////////////////////////////
// apply field security lock behaviors, if applicable //
////////////////////////////////////////////////////////
boolean isDenied = false;
if(field.getFieldSecurityLock() != null)
{
FieldSecurityLock.Behavior behavior = field.getFieldSecurityLock().getBehaviorForSession(qSession);
if(FieldSecurityLock.Behavior.DENY.equals(behavior))
{
isDenied = true;
}
}
if(!field.getIsHidden() && !isDenied)
if(!field.getIsHidden())
{
this.fields.put(fieldName, new QFrontendFieldMetaData(field));
}
@ -141,7 +124,7 @@ public class QFrontendTableMetaData
QTableMetaData joinTable = qInstance.getTable(exposedJoin.getJoinTable());
frontendExposedJoin.setLabel(exposedJoin.getLabel());
frontendExposedJoin.setIsMany(exposedJoin.getIsMany());
frontendExposedJoin.setJoinTable(new QFrontendTableMetaData(backendForTable, joinTable, includeFullMetaData, false));
frontendExposedJoin.setJoinTable(new QFrontendTableMetaData(actionInput, backendForTable, joinTable, includeFullMetaData, false));
for(String joinName : exposedJoin.getJoinPath())
{
frontendExposedJoin.addJoin(qInstance.getJoin(joinName));
@ -178,16 +161,16 @@ public class QFrontendTableMetaData
setCapabilities(backendForTable, tableMetaData);
readPermission = PermissionsHelper.hasTablePermission(tableMetaData.getName(), TablePermissionSubType.READ);
insertPermission = PermissionsHelper.hasTablePermission(tableMetaData.getName(), TablePermissionSubType.INSERT);
editPermission = PermissionsHelper.hasTablePermission(tableMetaData.getName(), TablePermissionSubType.EDIT);
deletePermission = PermissionsHelper.hasTablePermission(tableMetaData.getName(), TablePermissionSubType.DELETE);
readPermission = PermissionsHelper.hasTablePermission(actionInput, tableMetaData.getName(), TablePermissionSubType.READ);
insertPermission = PermissionsHelper.hasTablePermission(actionInput, tableMetaData.getName(), TablePermissionSubType.INSERT);
editPermission = PermissionsHelper.hasTablePermission(actionInput, tableMetaData.getName(), TablePermissionSubType.EDIT);
deletePermission = PermissionsHelper.hasTablePermission(actionInput, tableMetaData.getName(), TablePermissionSubType.DELETE);
QBackendMetaData backend = QContext.getQInstance().getBackend(tableMetaData.getBackendName());
QBackendMetaData backend = actionInput.getInstance().getBackend(tableMetaData.getBackendName());
if(backend != null && backend.getUsesVariants())
{
usesVariants = true;
variantTableLabel = QContext.getQInstance().getTable(backend.getVariantOptionsTableName()).getLabel();
variantTableLabel = actionInput.getInstance().getTable(backend.getVariantOptionsTableName()).getLabel();
}
}

View File

@ -23,38 +23,17 @@ package com.kingsrook.qqq.backend.core.model.metadata.security;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.session.QSession;
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
import java.util.List;
/*******************************************************************************
** Define, for a field, a lock that controls if users can or cannot see the field.
**
** The lock has a defaultBehavior, which is how the field should be treated, well,
** by default.
** The lock also references a securityKeyType; whose values, when looked up in
** the lock's keyValueBehaviors map, change the default behavior.
**
** For example, consider a lock with a keyType of 'internalOrExternalUser' (with
** possible values of 'internal' and 'external'), a defaultBehavior of DENY,
** and a keyValueBehaviors map containing internal => ALLOW. If a session has
** no security key of the internalOrExternalUser type, or a key with the value of
** 'external', then the lock's behavior will be the default (DENY). However,
** a key value of 'internal' would trigger the behavior specified for that key
** (ALLOW).
*******************************************************************************/
public class FieldSecurityLock
{
private static final QLogger LOG = QLogger.getLogger(FieldSecurityLock.class);
private String securityKeyType;
private Behavior defaultBehavior = Behavior.DENY;
private Map<Serializable, Behavior> keyValueBehaviors;
private String securityKeyType;
private Behavior defaultBehavior = Behavior.DENY;
private List<Serializable> overrideValues;
@ -110,6 +89,7 @@ public class FieldSecurityLock
/*******************************************************************************
** Getter for defaultBehavior
*******************************************************************************/
@ -142,82 +122,33 @@ public class FieldSecurityLock
/*******************************************************************************
** Getter for keyValueBehaviors
** Getter for overrideValues
*******************************************************************************/
public Map<Serializable, Behavior> getKeyValueBehaviors()
public List<Serializable> getOverrideValues()
{
return (this.keyValueBehaviors);
return (this.overrideValues);
}
/*******************************************************************************
** Setter for keyValueBehaviors
** Setter for overrideValues
*******************************************************************************/
public void setKeyValueBehaviors(Map<Serializable, Behavior> keyValueBehaviors)
public void setOverrideValues(List<Serializable> overrideValues)
{
this.keyValueBehaviors = keyValueBehaviors;
this.overrideValues = overrideValues;
}
/*******************************************************************************
** Fluent setter for keyValueBehaviors
** Fluent setter for overrideValues
*******************************************************************************/
public FieldSecurityLock withKeyValueBehaviors(Map<Serializable, Behavior> keyValueBehaviors)
public FieldSecurityLock withOverrideValues(List<Serializable> overrideValues)
{
this.keyValueBehaviors = keyValueBehaviors;
this.overrideValues = overrideValues;
return (this);
}
/*******************************************************************************
** Fluent setter for a single keyValueBehavior
*******************************************************************************/
public FieldSecurityLock withKeyValueBehavior(Serializable keyValue, Behavior behavior)
{
if(this.keyValueBehaviors == null)
{
this.keyValueBehaviors = new HashMap<>();
}
this.keyValueBehaviors.put(keyValue, behavior);
return (this);
}
/*******************************************************************************
**
*******************************************************************************/
public Behavior getBehaviorForSession(QSession session)
{
if(session != null && session.getSecurityKeyValues(this.securityKeyType) != null)
{
QSecurityKeyType securityKeyType = QContext.getQInstance().getSecurityKeyType(this.securityKeyType);
for(Serializable securityKeyValue : session.getSecurityKeyValues(this.securityKeyType))
{
try
{
if(securityKeyType.getValueType() != null)
{
securityKeyValue = ValueUtils.getValueAsFieldType(securityKeyType.getValueType(), securityKeyValue);
}
if(keyValueBehaviors.containsKey(securityKeyValue))
{
return keyValueBehaviors.get(securityKeyValue);
}
}
catch(Exception e)
{
LOG.warn("Error getting field behavior", e);
}
}
}
return getDefaultBehavior();
}
}

View File

@ -24,7 +24,6 @@ package com.kingsrook.qqq.backend.core.model.metadata.security;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.TopLevelMetaDataInterface;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
/*******************************************************************************
@ -38,8 +37,6 @@ public class QSecurityKeyType implements TopLevelMetaDataInterface
private String nullValueBehaviorKeyName;
private String possibleValueSourceName;
private QFieldType valueType;
/*******************************************************************************
@ -154,7 +151,6 @@ public class QSecurityKeyType implements TopLevelMetaDataInterface
}
/*******************************************************************************
** Getter for nullValueBehaviorKeyName
*******************************************************************************/
@ -185,34 +181,4 @@ public class QSecurityKeyType implements TopLevelMetaDataInterface
}
/*******************************************************************************
** Getter for valueType
*******************************************************************************/
public QFieldType getValueType()
{
return (this.valueType);
}
/*******************************************************************************
** Setter for valueType
*******************************************************************************/
public void setValueType(QFieldType valueType)
{
this.valueType = valueType;
}
/*******************************************************************************
** Fluent setter for valueType
*******************************************************************************/
public QSecurityKeyType withValueType(QFieldType valueType)
{
this.valueType = valueType;
return (this);
}
}

View File

@ -152,10 +152,10 @@ class PermissionsHelperTest extends BaseTest
AbstractTableActionInput actionInput = new InsertInput().withTableName(TABLE_NAME);
assertTrue(PermissionsHelper.hasTablePermission(TABLE_NAME, TablePermissionSubType.READ));
assertFalse(PermissionsHelper.hasTablePermission(TABLE_NAME, TablePermissionSubType.INSERT));
assertFalse(PermissionsHelper.hasTablePermission(TABLE_NAME, TablePermissionSubType.EDIT));
assertFalse(PermissionsHelper.hasTablePermission(TABLE_NAME, TablePermissionSubType.DELETE));
assertTrue(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, TablePermissionSubType.READ));
assertFalse(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, TablePermissionSubType.INSERT));
assertFalse(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, TablePermissionSubType.EDIT));
assertFalse(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, TablePermissionSubType.DELETE));
PermissionsHelper.checkTablePermissionThrowing(actionInput, TablePermissionSubType.READ);
assertThatThrownBy(() -> PermissionsHelper.checkTablePermissionThrowing(actionInput, TablePermissionSubType.INSERT)).isInstanceOf(QPermissionDeniedException.class);
assertThatThrownBy(() -> PermissionsHelper.checkTablePermissionThrowing(actionInput, TablePermissionSubType.EDIT)).isInstanceOf(QPermissionDeniedException.class);
@ -169,10 +169,10 @@ class PermissionsHelperTest extends BaseTest
AbstractTableActionInput actionInput = new InsertInput().withTableName(TABLE_NAME);
assertFalse(PermissionsHelper.hasTablePermission(TABLE_NAME, TablePermissionSubType.READ));
assertTrue(PermissionsHelper.hasTablePermission(TABLE_NAME, TablePermissionSubType.INSERT));
assertTrue(PermissionsHelper.hasTablePermission(TABLE_NAME, TablePermissionSubType.EDIT));
assertTrue(PermissionsHelper.hasTablePermission(TABLE_NAME, TablePermissionSubType.DELETE));
assertFalse(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, TablePermissionSubType.READ));
assertTrue(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, TablePermissionSubType.INSERT));
assertTrue(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, TablePermissionSubType.EDIT));
assertTrue(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, TablePermissionSubType.DELETE));
assertThatThrownBy(() -> PermissionsHelper.checkTablePermissionThrowing(actionInput, TablePermissionSubType.READ)).isInstanceOf(QPermissionDeniedException.class);
PermissionsHelper.checkTablePermissionThrowing(actionInput, TablePermissionSubType.INSERT);
PermissionsHelper.checkTablePermissionThrowing(actionInput, TablePermissionSubType.EDIT);
@ -244,10 +244,10 @@ class PermissionsHelperTest extends BaseTest
AbstractTableActionInput actionInput = new InsertInput().withTableName(TABLE_NAME);
assertTrue(PermissionsHelper.hasTablePermission(TABLE_NAME, TablePermissionSubType.READ));
assertFalse(PermissionsHelper.hasTablePermission(TABLE_NAME, TablePermissionSubType.INSERT));
assertFalse(PermissionsHelper.hasTablePermission(TABLE_NAME, TablePermissionSubType.EDIT));
assertFalse(PermissionsHelper.hasTablePermission(TABLE_NAME, TablePermissionSubType.DELETE));
assertTrue(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, TablePermissionSubType.READ));
assertFalse(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, TablePermissionSubType.INSERT));
assertFalse(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, TablePermissionSubType.EDIT));
assertFalse(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, TablePermissionSubType.DELETE));
PermissionsHelper.checkTablePermissionThrowing(actionInput, TablePermissionSubType.READ);
assertThatThrownBy(() -> PermissionsHelper.checkTablePermissionThrowing(actionInput, TablePermissionSubType.INSERT)).isInstanceOf(QPermissionDeniedException.class);
assertThatThrownBy(() -> PermissionsHelper.checkTablePermissionThrowing(actionInput, TablePermissionSubType.EDIT)).isInstanceOf(QPermissionDeniedException.class);
@ -261,10 +261,10 @@ class PermissionsHelperTest extends BaseTest
AbstractTableActionInput actionInput = new InsertInput().withTableName(TABLE_NAME);
assertFalse(PermissionsHelper.hasTablePermission(TABLE_NAME, TablePermissionSubType.READ));
assertTrue(PermissionsHelper.hasTablePermission(TABLE_NAME, TablePermissionSubType.INSERT));
assertFalse(PermissionsHelper.hasTablePermission(TABLE_NAME, TablePermissionSubType.EDIT));
assertFalse(PermissionsHelper.hasTablePermission(TABLE_NAME, TablePermissionSubType.DELETE));
assertFalse(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, TablePermissionSubType.READ));
assertTrue(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, TablePermissionSubType.INSERT));
assertFalse(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, TablePermissionSubType.EDIT));
assertFalse(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, TablePermissionSubType.DELETE));
assertThatThrownBy(() -> PermissionsHelper.checkTablePermissionThrowing(actionInput, TablePermissionSubType.READ)).isInstanceOf(QPermissionDeniedException.class);
PermissionsHelper.checkTablePermissionThrowing(actionInput, TablePermissionSubType.INSERT);
assertThatThrownBy(() -> PermissionsHelper.checkTablePermissionThrowing(actionInput, TablePermissionSubType.EDIT)).isInstanceOf(QPermissionDeniedException.class);
@ -581,7 +581,7 @@ class PermissionsHelperTest extends BaseTest
for(TablePermissionSubType permissionSubType : TablePermissionSubType.values())
{
assertTrue(PermissionsHelper.hasTablePermission(TABLE_NAME, permissionSubType), "Expected to have permission " + TABLE_NAME + ":" + permissionSubType);
assertTrue(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, permissionSubType), "Expected to have permission " + TABLE_NAME + ":" + permissionSubType);
PermissionsHelper.checkTablePermissionThrowing(actionInput, permissionSubType);
}
@ -600,7 +600,7 @@ class PermissionsHelperTest extends BaseTest
for(TablePermissionSubType permissionSubType : TablePermissionSubType.values())
{
assertFalse(PermissionsHelper.hasTablePermission(TABLE_NAME, permissionSubType));
assertFalse(PermissionsHelper.hasTablePermission(actionInput, TABLE_NAME, permissionSubType));
assertThatThrownBy(() -> PermissionsHelper.checkTablePermissionThrowing(actionInput, permissionSubType))
.isExactlyInstanceOf(QPermissionDeniedException.class);
}

View File

@ -1922,8 +1922,8 @@ public class QInstanceValidatorTest extends BaseTest
assertValidationFailureReasons((qInstance -> lockExtractor.apply(qInstance).setSecurityKeyType(" ")), "missing a securityKeyType");
assertValidationFailureReasons((qInstance -> lockExtractor.apply(qInstance).setSecurityKeyType("notAKeyType")), "unrecognized securityKeyType");
assertValidationFailureReasons((qInstance -> lockExtractor.apply(qInstance).setDefaultBehavior(null)), "missing a defaultBehavior");
assertValidationFailureReasons((qInstance -> lockExtractor.apply(qInstance).setKeyValueBehaviors(null)), "missing keyValueBehaviors");
assertValidationFailureReasons((qInstance -> lockExtractor.apply(qInstance).setKeyValueBehaviors(Collections.emptyMap())), "missing keyValueBehaviors");
assertValidationFailureReasons((qInstance -> lockExtractor.apply(qInstance).setOverrideValues(null)), "missing overrideValues");
assertValidationFailureReasons((qInstance -> lockExtractor.apply(qInstance).setOverrideValues(Collections.emptyList())), "missing overrideValues");
}

View File

@ -1,89 +0,0 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2024. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.model.metadata.frontend;
import java.util.function.Supplier;
import com.kingsrook.qqq.backend.core.BaseTest;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
import com.kingsrook.qqq.backend.core.model.metadata.security.FieldSecurityLock;
import com.kingsrook.qqq.backend.core.model.metadata.security.QSecurityKeyType;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.session.QSession;
import com.kingsrook.qqq.backend.core.utils.TestUtils;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
/*******************************************************************************
** Unit test for QFrontendTableMetaData
*******************************************************************************/
class QFrontendTableMetaDataTest extends BaseTest
{
/*******************************************************************************
**
*******************************************************************************/
@Test
void testFieldLocks()
{
QContext.getQInstance().addSecurityKeyType(new QSecurityKeyType()
.withName("allowedToSeeFirstName")
.withValueType(QFieldType.BOOLEAN));
FieldSecurityLock fieldSecurityLock = new FieldSecurityLock()
.withSecurityKeyType("allowedToSeeFirstName")
.withDefaultBehavior(FieldSecurityLock.Behavior.DENY)
.withKeyValueBehavior(true, FieldSecurityLock.Behavior.ALLOW);
QTableMetaData table = QContext.getQInstance().getTable(TestUtils.TABLE_NAME_PERSON_MEMORY);
table.getField("firstName").withFieldSecurityLock(fieldSecurityLock);
Supplier<QFrontendTableMetaData> run = () -> new QFrontendTableMetaData(QContext.getQInstance().getBackendForTable(TestUtils.TABLE_NAME_PERSON_MEMORY), table, true, false);
//////////////////////////////////////////////////////////////
// default session (no key) should NOT get to see firstName //
//////////////////////////////////////////////////////////////
assertFalse(run.get().getFields().containsKey("firstName"));
/////////////////////////////////////
// with the key=true, then allowed //
/////////////////////////////////////
QContext.setQSession(new QSession().withSecurityKeyValue("allowedToSeeFirstName", true));
assertTrue(run.get().getFields().containsKey("firstName"));
////////////////////////////////////////
// try a string version of the key... //
////////////////////////////////////////
QContext.setQSession(new QSession().withSecurityKeyValue("allowedToSeeFirstName", "true"));
assertTrue(run.get().getFields().containsKey("firstName"));
////////////////////////////
// try unrecognized value //
////////////////////////////
QContext.setQSession(new QSession().withSecurityKeyValue("allowedToSeeFirstName", "nope"));
assertFalse(run.get().getFields().containsKey("firstName"));
}
}

View File

@ -1,85 +0,0 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2024. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.model.metadata.security;
import com.kingsrook.qqq.backend.core.BaseTest;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
import com.kingsrook.qqq.backend.core.model.session.QSession;
import com.kingsrook.qqq.backend.core.utils.TestUtils;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/*******************************************************************************
** Unit test for FieldSecurityLock
*******************************************************************************/
class FieldSecurityLockTest extends BaseTest
{
/*******************************************************************************
**
*******************************************************************************/
@Test
void testGetBehaviorForSession()
{
QContext.getQInstance().addSecurityKeyType(new QSecurityKeyType()
.withName("foo")
.withValueType(QFieldType.STRING));
FieldSecurityLock fieldSecurityLock = new FieldSecurityLock()
.withSecurityKeyType("foo")
.withDefaultBehavior(FieldSecurityLock.Behavior.DENY)
.withKeyValueBehavior("bar", FieldSecurityLock.Behavior.ALLOW)
.withKeyValueBehavior("baz", FieldSecurityLock.Behavior.ALLOW)
.withKeyValueBehavior("boo", FieldSecurityLock.Behavior.DENY);
QContext.getQInstance().getTable(TestUtils.TABLE_NAME_PERSON_MEMORY)
.getField("firstName").withFieldSecurityLock(fieldSecurityLock);
////////////////////////////
// no key value = default //
////////////////////////////
assertEquals(FieldSecurityLock.Behavior.DENY, fieldSecurityLock.getBehaviorForSession(new QSession()));
/////////////////////////////////////////////////
// values specified get the behavior specified //
/////////////////////////////////////////////////
assertEquals(FieldSecurityLock.Behavior.ALLOW, fieldSecurityLock.getBehaviorForSession(new QSession().withSecurityKeyValue("foo", "bar")));
assertEquals(FieldSecurityLock.Behavior.ALLOW, fieldSecurityLock.getBehaviorForSession(new QSession().withSecurityKeyValue("foo", "baz")));
assertEquals(FieldSecurityLock.Behavior.DENY, fieldSecurityLock.getBehaviorForSession(new QSession().withSecurityKeyValue("foo", "boo")));
//////////////////////////////////////////////
// unrecognized values get default behavior //
//////////////////////////////////////////////
assertEquals(FieldSecurityLock.Behavior.DENY, fieldSecurityLock.getBehaviorForSession(new QSession().withSecurityKeyValue("foo", "huh")));
/////////////////////////////////////////////////
// if multiple key values, the first one wins. //
/////////////////////////////////////////////////
assertEquals(FieldSecurityLock.Behavior.ALLOW, fieldSecurityLock.getBehaviorForSession(new QSession().withSecurityKeyValue("foo", "bar").withSecurityKeyValue("foo", "boo")));
assertEquals(FieldSecurityLock.Behavior.DENY, fieldSecurityLock.getBehaviorForSession(new QSession().withSecurityKeyValue("foo", "boo").withSecurityKeyValue("foo", "foo")));
}
}

View File

@ -660,7 +660,7 @@ public class TestUtils
.withField(new QFieldMetaData("total", QFieldType.DECIMAL).withDisplayFormat(DisplayFormat.CURRENCY).withFieldSecurityLock(new FieldSecurityLock()
.withSecurityKeyType(SECURITY_KEY_TYPE_INTERNAL_OR_EXTERNAL)
.withDefaultBehavior(FieldSecurityLock.Behavior.DENY)
.withKeyValueBehavior("internal", FieldSecurityLock.Behavior.ALLOW)
.withOverrideValues(List.of("internal"))
));
}