Files
qt5-legatus-legacy/Lts/Services/OperatorManagement/object_operator.cpp
T
2026-08-13 18:33:10 +02:00

376 lines
12 KiB
C++
Executable File

/**
* Handler for the HMI language
* $Id$
* $HeadURL$
* $Author$
*/
#include "object_operator.h"
#include "main_handler.h"
#include <LtsUtilsCore/dds_vector.h>
#include <ngldb/dbtransaction.h>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
namespace OperatorManagement
{
ObjectOperator::ObjectOperator(MainHandler *mainHandler)
: m_mainHandler(mainHandler)
, m_originalPrimaryGroupId(0)
, m_logger(getLogger("ObjectOperator"))
{
}
ObjectOperator::~ObjectOperator()
{
m_mainHandler->dds()->dts()->removeUserByKey(m_data.id);
}
Core::FunctionReplyObject ObjectOperator::createObject(const Database::OpmOperator &data,
const QVector<Database::OpmOperatorExercise> &vec)
{
m_data = data;
m_dataExercise = vec;
m_originalPrimaryGroupId = data.primaryGroupId;
if (m_data.id <= 0)
{
if (!m_mainHandler->db()->insert(m_data))
return Core::FunctionReplyObject(0, tr_lts("dds", "Error inserting operator into database."));
}
return updateEffectiveAcls(calculateEffectiveAcls());
}
Core::FunctionReplyObject ObjectOperator::updateEffectiveAcls(const QSet<int> &effectiveAcls)
{
m_effectiveAcls = effectiveAcls;
onPublishData();
return Core::FunctionReplyObject(m_data.id);
}
Core::FunctionReplyObject ObjectOperator::updateExercises(const std::vector<int> &exercises, bool dontUpdateDb)
{
if (m_exercises == exercises)
return Core::FunctionReplyObject(m_data.id);
if (dontUpdateDb)
{
m_exercises = exercises;
onPublishData();
return Core::FunctionReplyObject(m_data.id);
}
// Remove all an set them all new...
if (!m_mainHandler->db()->removeOpmOperatorExerciseByOperatorId(m_data.id))
return Core::FunctionReplyObject(0, tr_lts("dds", "Could not remove exercises from operator with id %1 in database.")).arg(m_data.id);
m_exercises.clear();
// insert can fail due to (deleted) exerciseId
m_mainHandler->db()->setEmitMessageOnError(false);
for (int exerciseId : exercises)
{
Database::OpmOperatorExercise mapping;
mapping.operatorId = m_data.id;
mapping.exerciseId = exerciseId;
bool add_to_map = true;
//for (const auto &ooe : copy)
for(int i = 0; i< m_dataExercise.size(); ++i)
{
if (m_dataExercise.at(i).exerciseId != exerciseId)
continue;
add_to_map = false;
mapping.visibleParties = m_dataExercise.at(i).visibleParties;
//replace internal vector
auto data = m_dataExercise.at(i);
data.visibleParties = mapping.visibleParties;
m_dataExercise.replace(i,data);
}
if (mapping.visibleParties().empty())
{
DEBUG_LOG(m_logger)<< "Update Operator visible Parties for Execise: No parties found for " << exerciseId << " use default (ex0)";
// Add default visibleParties from ex0
mapping.visibleParties = m_data.visibleParties;
}
if (!m_mainHandler->db()->insert(mapping))
INFO_LOG(m_logger) << "Can not add operator " << mapping.operatorId << " to exercise " << exerciseId << " - exercise does no longer exist";
else
{
if (std::find(m_exercises.begin(), m_exercises.end(), exerciseId) == m_exercises.end())
m_exercises.push_back(exerciseId);
if (add_to_map)
m_dataExercise.push_back(mapping);
}
}
m_mainHandler->db()->setEmitMessageOnError(true);
onPublishData();
return Core::FunctionReplyObject(m_data.id);
}
Core::FunctionReplyObject ObjectOperator::updateObject(const Database::OpmOperator &data)
{
m_data.name = data.name;
DEBUG_LOG(m_logger) << "ObjectOperator::updateObject"
<< " data.id = " << data.id
<< " data.rolePresetId = " << data.rolePresetId;
m_data.description = data.description;
m_data.password = data.password;
m_data.image = data.image;
m_data.visibleParties = data.visibleParties;
m_data.workstationIp = data.workstationIp;
m_data.workstationId = data.workstationId;
m_data.projectionPriority = data.projectionPriority;
m_data.audioChannelPriority = data.audioChannelPriority;
m_data.primaryGroupId = m_originalPrimaryGroupId;
m_data.rolePresetId = data.rolePresetId;
m_data.properties = data.properties;
if (!m_mainHandler->db()->update(m_data))
{
ERROR_LOG(m_logger)<< "Error updating Operator in database: " << m_mainHandler->db()->getLastError().text();
return Core::FunctionReplyObject(0, tr_lts("dds", "Error updating operator in database."));
}
m_data.primaryGroupId = data.primaryGroupId;
onPublishData();
return Core::FunctionReplyObject(m_data.id);
}
Core::FunctionReplyObject ObjectOperator::updateOperatorExercise(const Database::OpmOperatorExercise &data)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << data.operatorId << " " << data.exerciseId;
// insert can fail due to (deleted) exerciseId
m_mainHandler->db()->setEmitMessageOnError(false);
for (int i=0; i < m_dataExercise.size(); ++i)
{
DEBUG_LOG(m_logger) << "** m_dataExercise.at(" << i << "): " << m_dataExercise.at(i).exerciseId << "==" << data.exerciseId;
if (m_dataExercise.at(i).exerciseId != data.exerciseId)
continue;
Database::OpmOperatorExercise mapping = m_dataExercise.at(i);
mapping.hiddenParties = data.hiddenParties;
mapping.visibleParties = data.visibleParties;
mapping.properties = data.properties;
m_dataExercise.replace(i, mapping);
DEBUG_LOG(m_logger) << "** m_dataExercise.at(" << i << "): " << m_dataExercise.at(i).operatorId << ", "
<< m_dataExercise.at(i).exerciseId << ", "
<< m_dataExercise.at(i).visibleParties.toPgString() << ", "
<< m_dataExercise.at(i).hiddenParties.toPgString();
DEBUG_LOG(m_logger) << "** mapping: " << mapping.operatorId << ", "
<< mapping.exerciseId << ", "
<< mapping.visibleParties.toPgString() << ", "
<< mapping.hiddenParties.toPgString();
if (!m_mainHandler->db()->update(mapping))
ERROR_LOG(m_logger)<< "Error updating OperatorExecise in database: " << m_mainHandler->db()->getLastError().text();
}
m_mainHandler->db()->setEmitMessageOnError(true);
onPublishData();
return Core::FunctionReplyObject(m_data.id);
}
Core::FunctionReplyObject ObjectOperator::removeObject()
{
if (!m_mainHandler->db()->removeOpmOperator(m_data.id))
return Core::FunctionReplyObject(m_data.id, tr_lts("dds", "Operator with id %1 can not be removed.")).arg(m_data.id);
if (!m_mainHandler->dts()->removeUserByKey(m_data.id))
return Core::FunctionReplyObject(m_data.id, tr_lts("dds", "Operator with id %1 can not be taken from DDS.")).arg(m_data.id);
return Core::FunctionReplyObject(m_data.id);
}
Core::FunctionReplyObject ObjectOperator::setPrimaryGroupId(int primaryGroupId)
{
// Todo: Sanity: Check, if primaryGroupId is type OperatorGroup.
m_data.primaryGroupId = primaryGroupId;
return updateEffectiveAcls(calculateEffectiveAcls());
}
bool ObjectOperator::saveSettings(const QByteArray &settings)
{
if (!m_settings.id)
{
QVector<Database::OpmSettings> tmp;
m_mainHandler->db()->selectByOperatorId(tmp, m_data.id);
// nothing loaded -> insert new
if (tmp.isEmpty())
{
m_settings.operatorId = m_data.id;
if (!m_mainHandler->db()->insert(m_settings))
return false;
}
else
m_settings = tmp.first();
}
m_settings.settings = settings;
return m_mainHandler->db()->update(m_settings);
}
bool ObjectOperator::loadSettings(QByteArray &settings)
{
if (!m_settings.id)
{
QVector<Database::OpmSettings> tmp;
if (!m_mainHandler->db()->selectByOperatorId(tmp, m_data.id))
return false;
if (!tmp.isEmpty())
m_settings = tmp.first();
m_settings.operatorId = m_data.id;
}
settings = m_settings.settings;
return true;
}
void ObjectOperator::reloadAcls(bool force)
{
const QSet<int> calculatedAcls = calculateEffectiveAcls();
// QStringList stringList;
// for (int acl : calculatedAcls)
// stringList << QString::number(acl);
// DEBUG_LOG(m_logger) << "Effective ACLs for Operator " << m_data.name << "(id: " << m_data.id << "): " << stringList.join(QLatin1String(", "));
if (force || m_effectiveAcls != calculatedAcls)
updateEffectiveAcls(calculatedAcls);
}
static inline void addValuesToSet(const QMultiMap<int, int> &in, const int key, QSet<int> &out)
{
auto it = in.find(key);
while (it != in.end() && it.key() == key)
{
out += it.value();
++it;
}
}
QSet<int> ObjectOperator::calculateEffectiveAcls() const
{
QMultiMap<int, int> groupMap;
QMultiMap<int, int> allowMap;
QMultiMap<int, int> denyMap;
auto cbGroup = [&groupMap] (const Database::OpmGroupGroup &group)
{
groupMap.insert(group.groupId, group.isMemberOfGroupId);
};
m_mainHandler->db()->select(cbGroup);
int i = 0;
// Initial
QList<int> effectiveGroups(groupMap.values(m_data.primaryGroupId));
// Now rekursive
while (i < effectiveGroups.size())
{
const QList<int> values = groupMap.values(effectiveGroups.at(i++));
for (int value : values)
if (!effectiveGroups.contains(value))
effectiveGroups << value;
}
auto cbAllow = [&allowMap] (const Database::OpmAclAllow &all)
{
allowMap.insert(all.groupId, all.aclId);
};
m_mainHandler->db()->select(cbAllow);
auto cbDeny = [&denyMap] (const Database::OpmAclDeny &den)
{
denyMap.insert(den.groupId, den.aclId);
};
m_mainHandler->db()->select(cbDeny);
QSet<int> allowances;
QSet<int> denials;
for (int group : qAsConst(effectiveGroups))
{
addValuesToSet(allowMap, group, allowances);
addValuesToSet(denyMap, group, denials);
}
allowances -= denials;
return allowances;
}
void ObjectOperator::onPublishData()
{
OperatorManagement::User op;
op.id(m_data.id);
op.name(m_data.name.toStdString());
op.description(m_data.description.toStdString());
op.primaryGroupId(m_data.primaryGroupId);
op.rolePresetId(m_data.rolePresetId);
op.effectiveAcls() = LtsUtils::convert<std::vector<int32_t>>(m_effectiveAcls);
auto vpbe = toDdsData(m_dataExercise);
// Append Visible Parties Template (= exId == 0)
QJsonArray adlerAllowedArray;
for (int currentParty : m_data.visibleParties())
adlerAllowedArray.append(currentParty);
QJsonObject adlerAllowedObject;
adlerAllowedObject.insert(QStringLiteral("adlerAllowed"), adlerAllowedArray);
QJsonDocument adlerAllowedDocument(adlerAllowedObject);
vpbe.push_back(OperatorManagement::PartiesByExercise(0, m_data.visibleParties(), std::vector<int>(),
adlerAllowedDocument.toJson(QJsonDocument::Compact).toStdString()));
op.visiblePartiesByExercise(vpbe);
op.exerciseIds(m_exercises);
op.image() = LtsUtils::convert<std::vector<uint8_t>>(m_data.image);
op.workstationIp(m_data.workstationIp);
op.workstationId(m_data.workstationId.toInt());
op.projectionPriority(m_data.projectionPriority);
op.audioChannelPriority(m_data.audioChannelPriority);
op.rolePresetId(m_data.rolePresetId);
op.properties(m_data.properties.toStdString());
INFO_LOG(m_logger) << "Publish OpmOperator-data to dds (" << m_data.id
<< " rolePresetId =" << m_data.rolePresetId
<< ") ...";
if (!m_mainHandler->dts()->publish(op))
ERROR_LOG(m_logger) << "Error publishing OpmOperator-data to dds";
}
std::vector<OperatorManagement::PartiesByExercise> ObjectOperator::toDdsData(const QVector<Database::OpmOperatorExercise> &dbData)
{
std::vector<PartiesByExercise> ddsData;
for (const Database::OpmOperatorExercise &ooe : dbData)
{
PartiesByExercise pbe;
pbe.exerciseId(ooe.exerciseId);
pbe.visibleParties();
pbe.hiddenParties();
std::vector<int> visibleParty;
for (const auto &elem : ooe.visibleParties())
{
visibleParty.push_back(elem);
}
pbe.visibleParties().set(visibleParty);
std::vector<int> hiddenParty;
for (const auto &elem : ooe.hiddenParties())
{
hiddenParty.push_back(elem);
}
pbe.hiddenParties().set(hiddenParty);
pbe.properties(ooe.properties.toStdString());
ddsData.push_back(pbe);
}
return ddsData;
}
} // Namespace OperatorManagement