mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Initial checkin
This commit is contained in:
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. 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.actions.audits;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import com.kingsrook.qqq.backend.core.actions.AbstractQActionFunction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.audits.AuditInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.audits.AuditOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
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.model.session.QUser;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Insert an audit (e.g., the same one) against 1 or more records.
|
||||
**
|
||||
** Takes care of managing the foreign key tables.
|
||||
**
|
||||
** Enforces that security key values are provided, if the table has any.
|
||||
*******************************************************************************/
|
||||
public class AuditAction extends AbstractQActionFunction<AuditInput, AuditOutput>
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(AuditAction.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static void execute(String tableName, Integer recordId, Map<String, Serializable> securityKeyValues, String message)
|
||||
{
|
||||
new AuditAction().execute(new AuditInput()
|
||||
.withAuditTableName(tableName)
|
||||
.withRecordIdList(List.of(recordId))
|
||||
.withSecurityKeyValues(securityKeyValues)
|
||||
.withMessage(message));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public AuditOutput execute(AuditInput input)
|
||||
{
|
||||
AuditOutput auditOutput = new AuditOutput();
|
||||
try
|
||||
{
|
||||
QTableMetaData table = QContext.getQInstance().getTable(input.getAuditTableName());
|
||||
if(table == null)
|
||||
{
|
||||
throw (new QException("Requested audit for an unrecognized table name: " + input.getAuditTableName()));
|
||||
}
|
||||
|
||||
for(RecordSecurityLock recordSecurityLock : CollectionUtils.nonNullList(table.getRecordSecurityLocks()))
|
||||
{
|
||||
if(input.getSecurityKeyValues() == null || !input.getSecurityKeyValues().containsKey(recordSecurityLock.getSecurityKeyType()))
|
||||
{
|
||||
throw (new QException("Missing securityKeyValue [" + recordSecurityLock.getSecurityKeyType() + "] in audit request for table " + input.getAuditTableName()));
|
||||
}
|
||||
}
|
||||
|
||||
Integer auditTableId = getIdForName("auditTable", input.getAuditTableName());
|
||||
Integer auditUserId = getIdForName("auditUser", Objects.requireNonNullElse(input.getAuditUserName(), getSessionUserName()));
|
||||
Instant timestamp = Objects.requireNonNullElse(input.getTimestamp(), Instant.now());
|
||||
|
||||
List<QRecord> auditRecords = new ArrayList<>();
|
||||
for(Integer recordId : input.getRecordIdList())
|
||||
{
|
||||
QRecord record = new QRecord()
|
||||
.withValue("auditTableId", auditTableId)
|
||||
.withValue("auditUserId", auditUserId)
|
||||
.withValue("timestamp", timestamp)
|
||||
.withValue("message", input.getMessage())
|
||||
.withValue("recordId", recordId);
|
||||
|
||||
if(input.getSecurityKeyValues() != null)
|
||||
{
|
||||
for(Map.Entry<String, Serializable> entry : input.getSecurityKeyValues().entrySet())
|
||||
{
|
||||
record.setValue(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
auditRecords.add(record);
|
||||
}
|
||||
|
||||
InsertInput insertInput = new InsertInput();
|
||||
insertInput.setTableName("audit");
|
||||
insertInput.setRecords(auditRecords);
|
||||
new InsertAction().execute(insertInput);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.error("Error performing an audit", e);
|
||||
}
|
||||
return (auditOutput);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static String getSessionUserName()
|
||||
{
|
||||
QUser user = QContext.getQSession().getUser();
|
||||
if(user == null)
|
||||
{
|
||||
return ("Unknown");
|
||||
}
|
||||
return (user.getFullName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private Integer getIdForName(String tableName, String nameValue) throws QException
|
||||
{
|
||||
Integer id = fetchIdFromName(tableName, nameValue);
|
||||
if(id != null)
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
LOG.debug("Inserting " + tableName + " named " + nameValue);
|
||||
InsertInput insertInput = new InsertInput();
|
||||
insertInput.setTableName(tableName);
|
||||
QRecord record = new QRecord().withValue("name", nameValue);
|
||||
|
||||
if(tableName.equals("auditTable"))
|
||||
{
|
||||
QTableMetaData table = QContext.getQInstance().getTable(nameValue);
|
||||
if(table != null)
|
||||
{
|
||||
record.setValue("label", table.getLabel());
|
||||
}
|
||||
}
|
||||
|
||||
insertInput.setRecords(List.of(record));
|
||||
InsertOutput insertOutput = new InsertAction().execute(insertInput);
|
||||
id = insertOutput.getRecords().get(0).getValueInteger("id");
|
||||
if(id != null)
|
||||
{
|
||||
return id;
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// assume this may mean a dupe-key - so - try another fetch below //
|
||||
////////////////////////////////////////////////////////////////////
|
||||
LOG.debug("Caught error inserting " + tableName + " named " + nameValue + " - will try to re-fetch", e);
|
||||
}
|
||||
|
||||
id = fetchIdFromName(tableName, nameValue);
|
||||
if(id != null)
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
/////////////
|
||||
// give up //
|
||||
/////////////
|
||||
throw (new QException("Unable to get id for " + tableName + " named " + nameValue));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static Integer fetchIdFromName(String tableName, String nameValue) throws QException
|
||||
{
|
||||
GetInput getInput = new GetInput();
|
||||
getInput.setTableName(tableName);
|
||||
getInput.setUniqueKey(Map.of("name", nameValue));
|
||||
GetOutput getOutput = new GetAction().execute(getInput);
|
||||
if(getOutput.getRecord() != null)
|
||||
{
|
||||
return (getOutput.getRecord().getValueInteger("id"));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. 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.actions.audits;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class AuditInput extends AbstractActionInput
|
||||
{
|
||||
private String auditTableName;
|
||||
private String auditUserName;
|
||||
private Instant timestamp;
|
||||
private String message;
|
||||
private List<Integer> recordIdList;
|
||||
|
||||
private Map<String, Serializable> securityKeyValues;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for auditTableName
|
||||
*******************************************************************************/
|
||||
public String getAuditTableName()
|
||||
{
|
||||
return (this.auditTableName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for auditTableName
|
||||
*******************************************************************************/
|
||||
public void setAuditTableName(String auditTableName)
|
||||
{
|
||||
this.auditTableName = auditTableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for auditTableName
|
||||
*******************************************************************************/
|
||||
public AuditInput withAuditTableName(String auditTableName)
|
||||
{
|
||||
this.auditTableName = auditTableName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for auditUserName
|
||||
*******************************************************************************/
|
||||
public String getAuditUserName()
|
||||
{
|
||||
return (this.auditUserName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for auditUserName
|
||||
*******************************************************************************/
|
||||
public void setAuditUserName(String auditUserName)
|
||||
{
|
||||
this.auditUserName = auditUserName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for auditUserName
|
||||
*******************************************************************************/
|
||||
public AuditInput withAuditUserName(String auditUserName)
|
||||
{
|
||||
this.auditUserName = auditUserName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for timestamp
|
||||
*******************************************************************************/
|
||||
public Instant getTimestamp()
|
||||
{
|
||||
return (this.timestamp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for timestamp
|
||||
*******************************************************************************/
|
||||
public void setTimestamp(Instant timestamp)
|
||||
{
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for timestamp
|
||||
*******************************************************************************/
|
||||
public AuditInput withTimestamp(Instant timestamp)
|
||||
{
|
||||
this.timestamp = timestamp;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for message
|
||||
*******************************************************************************/
|
||||
public String getMessage()
|
||||
{
|
||||
return (this.message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for message
|
||||
*******************************************************************************/
|
||||
public void setMessage(String message)
|
||||
{
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for message
|
||||
*******************************************************************************/
|
||||
public AuditInput withMessage(String message)
|
||||
{
|
||||
this.message = message;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for recordIdList
|
||||
*******************************************************************************/
|
||||
public List<Integer> getRecordIdList()
|
||||
{
|
||||
return (this.recordIdList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for recordIdList
|
||||
*******************************************************************************/
|
||||
public void setRecordIdList(List<Integer> recordIdList)
|
||||
{
|
||||
this.recordIdList = recordIdList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for recordIdList
|
||||
*******************************************************************************/
|
||||
public AuditInput withRecordIdList(List<Integer> recordIdList)
|
||||
{
|
||||
this.recordIdList = recordIdList;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for securityKeyValues
|
||||
*******************************************************************************/
|
||||
public Map<String, Serializable> getSecurityKeyValues()
|
||||
{
|
||||
return (this.securityKeyValues);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for securityKeyValues
|
||||
*******************************************************************************/
|
||||
public void setSecurityKeyValues(Map<String, Serializable> securityKeyValues)
|
||||
{
|
||||
this.securityKeyValues = securityKeyValues;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for securityKeyValues
|
||||
*******************************************************************************/
|
||||
public AuditInput withSecurityKeyValues(Map<String, Serializable> securityKeyValues)
|
||||
{
|
||||
this.securityKeyValues = securityKeyValues;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. 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.actions.audits;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class AuditOutput extends AbstractActionOutput
|
||||
{
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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.audits;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
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.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class AuditsMetaDataProvider
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void defineAll(QInstance instance, String backendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
|
||||
{
|
||||
defineStandardAuditTables(instance, backendName, backendDetailEnricher);
|
||||
defineStandardAuditPossibleValueSources(instance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void defineStandardAuditTables(QInstance instance, String backendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
|
||||
{
|
||||
for(QTableMetaData tableMetaData : defineStandardAuditTables(backendName, backendDetailEnricher))
|
||||
{
|
||||
instance.addTable(tableMetaData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void defineStandardAuditPossibleValueSources(QInstance instance)
|
||||
{
|
||||
instance.addPossibleValueSource(new QPossibleValueSource()
|
||||
.withName("auditTable")
|
||||
.withTableName("auditTable")
|
||||
);
|
||||
|
||||
instance.addPossibleValueSource(new QPossibleValueSource()
|
||||
.withName("auditUser")
|
||||
.withTableName("auditUser")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private List<QTableMetaData> defineStandardAuditTables(String backendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
|
||||
{
|
||||
List<QTableMetaData> rs = new ArrayList<>();
|
||||
rs.add(enrich(backendDetailEnricher, defineAuditUserTable(backendName)));
|
||||
rs.add(enrich(backendDetailEnricher, defineAuditTableTable(backendName)));
|
||||
rs.add(enrich(backendDetailEnricher, defineAuditTable(backendName)));
|
||||
return (rs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private QTableMetaData enrich(Consumer<QTableMetaData> backendDetailEnricher, QTableMetaData table)
|
||||
{
|
||||
if(backendDetailEnricher != null)
|
||||
{
|
||||
backendDetailEnricher.accept(table);
|
||||
}
|
||||
return (table);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private QTableMetaData defineAuditTableTable(String backendName)
|
||||
{
|
||||
return new QTableMetaData()
|
||||
.withName("auditTable")
|
||||
.withBackendName(backendName)
|
||||
.withRecordLabelFormat("%s")
|
||||
.withRecordLabelFields("label")
|
||||
.withPrimaryKeyField("id")
|
||||
.withUniqueKey(new UniqueKey("name"))
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withField(new QFieldMetaData("name", QFieldType.STRING))
|
||||
.withField(new QFieldMetaData("label", QFieldType.STRING))
|
||||
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME))
|
||||
.withField(new QFieldMetaData("modifyDate", QFieldType.DATE_TIME));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private QTableMetaData defineAuditUserTable(String backendName)
|
||||
{
|
||||
return new QTableMetaData()
|
||||
.withName("auditUser")
|
||||
.withBackendName(backendName)
|
||||
.withRecordLabelFormat("%s")
|
||||
.withRecordLabelFields("name")
|
||||
.withPrimaryKeyField("id")
|
||||
.withUniqueKey(new UniqueKey("name"))
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withField(new QFieldMetaData("name", QFieldType.STRING))
|
||||
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME))
|
||||
.withField(new QFieldMetaData("modifyDate", QFieldType.DATE_TIME));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private QTableMetaData defineAuditTable(String backendName)
|
||||
{
|
||||
return new QTableMetaData()
|
||||
.withName("audit")
|
||||
.withBackendName(backendName)
|
||||
.withRecordLabelFormat("%s")
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withField(new QFieldMetaData("auditTableId", QFieldType.INTEGER).withPossibleValueSourceName("auditTable"))
|
||||
.withField(new QFieldMetaData("auditUserId", QFieldType.INTEGER).withPossibleValueSourceName("auditUser"))
|
||||
.withField(new QFieldMetaData("recordId", QFieldType.INTEGER))
|
||||
.withField(new QFieldMetaData("message", QFieldType.STRING).withMaxLength(250).withBehavior(ValueTooLongBehavior.TRUNCATE_ELLIPSIS))
|
||||
.withField(new QFieldMetaData("timestamp", QFieldType.DATE_TIME));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. 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.actions.audits;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.audits.AuditsMetaDataProvider;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QUser;
|
||||
import com.kingsrook.qqq.backend.core.processes.utils.GeneralProcessUtils;
|
||||
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 AuditAction
|
||||
*******************************************************************************/
|
||||
class AuditActionTest extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test() throws QException
|
||||
{
|
||||
QInstance qInstance = TestUtils.defineInstance();
|
||||
new AuditsMetaDataProvider().defineAll(qInstance, TestUtils.MEMORY_BACKEND_NAME, null);
|
||||
|
||||
String userName = "John Doe";
|
||||
QContext.init(qInstance, new QSession().withUser(new QUser().withFullName(userName)));
|
||||
|
||||
Integer recordId = 1701;
|
||||
AuditAction.execute(TestUtils.TABLE_NAME_PERSON_MEMORY, recordId, Map.of(), "Test Audit");
|
||||
|
||||
/////////////////////////////////////
|
||||
// make sure things can be fetched //
|
||||
/////////////////////////////////////
|
||||
GeneralProcessUtils.getRecordByFieldOrElseThrow(null, "auditTable", "name", TestUtils.TABLE_NAME_PERSON_MEMORY);
|
||||
GeneralProcessUtils.getRecordByFieldOrElseThrow(null, "auditUser", "name", userName);
|
||||
QRecord auditRecord = GeneralProcessUtils.getRecordByFieldOrElseThrow(null, "audit", "recordId", recordId);
|
||||
assertEquals("Test Audit", auditRecord.getValueString("message"));
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user