mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +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