Files
qt-migration-legatus/qt6-after/qt6-migrated-legatus/Lts/Services/OperatorManagement/handler_operator.cpp
T
berrux-dev 95071993f5 Migrates Participant and OperatorManagement to generated rtiddsgen API
Converts accessor calls to plain member access in ppm and opm services and plugins.
2026-09-21 02:46:44 +02:00

686 lines
24 KiB
C++
Executable File

/**
* Handler for all exercise objects
* $Id$
* $HeadURL$
* $Author$
* Created by Hanna E. Rathje, SLSE, 2015-09-03
*/
#include "handler_operator.h"
#include "handler_locked_topics.h"
#include "handler_active_apps.h"
#include "object_operator.h"
#include "handler_group.h"
#include "opm_db.h"
#include <QCryptographicHash>
#include <QtCore/QSet>
#include <QtCore/QTimer>
#include <LtsUtilsCore/dds_vector.h>
namespace OperatorManagement
{
HandlerOperator::HandlerOperator(MainHandler *mainHandler)
: Interface::Fts::OperatorChangePasswordRequestHandler(mainHandler->fts())
, Interface::Fts::OperatorCreateModifyRequestHandler(mainHandler->fts())
, Interface::Fts::OperatorRemoveRequestHandler(mainHandler->fts())
, Interface::Fts::OperatorLoginRequestHandler(mainHandler->fts())
, Interface::Fts::OperatorLogoutRequestHandler(mainHandler->fts())
, Interface::Fts::OperatorGetSetSettingsRequestHandler(mainHandler->fts())
, Interface::Fts::OperatorApplyForeignAclsRequestHandler(mainHandler->fts())
, Interface::Fts::OperatorUpdateVisiblePartiesByExerciseRequestHandler(mainHandler->fts())
, m_aliveCheckTimer(new QTimer(this))
, m_mainHandler(mainHandler)
, m_logger(getLogger("HandlerOperator"))
{
connect(m_aliveCheckTimer, &QTimer::timeout, this, &HandlerOperator::onCheckAliveTimeout);
m_aliveCheckTimer->setInterval(10000);
m_aliveCheckTimer->setSingleShot(false);
m_aliveCheckTimer->start();
}
HandlerOperator::~HandlerOperator()
{
qDeleteAll(m_operatorObjMap);
}
bool HandlerOperator::init()
{
QVector<Database::OpmOperatorExercise> exMappingVec;
m_mainHandler->db()->select(exMappingVec);
QVector<Database::OpmOperator> dataVec;
// read all Operators from database
if (!m_mainHandler->db()->select(dataVec))
{
ERROR_LOG(m_logger) << "Error reading data from database!";
return true;
}
QVector<Database::OpmOperatorExercise> partyExerciseVec;
// read all Operators from database
if (!m_mainHandler->db()->select(partyExerciseVec))
{
ERROR_LOG(m_logger) << "Error reading data from database!";
return true;
}
QMap<int, QVector<Database::OpmOperatorExercise> > opMap;
for (const auto &elem : partyExerciseVec)
{
INFO_LOG(m_logger) << "---------- elem.operatorId:" << elem.operatorId
<< ", elem size " << elem.visibleParties().size();
opMap[elem.operatorId] << elem;
}
INFO_LOG(m_logger) << "------- opMap size" << opMap.size();
OperatorManagement::OperatorWorkstationAlive alive;
alive.lastAlive = QDateTime::currentMSecsSinceEpoch();
for (const Database::OpmOperator &op : qAsConst(dataVec))
{
ObjectOperator *ifs(new ObjectOperator(m_mainHandler));
Core::FunctionReplyObject ret = ifs->createObject(op, opMap[op.id]);
if (ret.error())
{
delete ifs;
ERROR_LOG(m_logger) << ret();
return false;
}
if (m_logger.isDebugEnabled())
{
QStringList stringList;
const auto &acls = ifs->effectiveAcls();
stringList.reserve(acls.size());
for (int acl : acls)
stringList << QString::number(acl);
DEBUG_LOG(m_logger) << "Effective ACLs for Operator " << op.name << "(id: " << op.id << "): "
<< stringList.join(QLatin1String(", "));
}
ifs->updateExercises(getExercisesForOperator(exMappingVec, op.id), true);
m_operatorObjMap.insert(ifs->getId(), ifs);
if (!op.workstationId.isNull())
{
alive.operatorId = op.id;
alive.workstationId = op.workstationId.toInt();
onOperatorWorkstationAliveChanged(alive, DataModification::eAdded);
}
}
auto dtc = m_mainHandler->dtc();
connect(dtc.get(), &Interface::Dtc::operatorWorkstationAliveChanged,
this, &HandlerOperator::onOperatorWorkstationAliveChanged);
dtc->enableOperatorWorkstationAlive();
DEBUG_LOG(m_logger) << "m_exeObjMap.size() = " << m_operatorObjMap.size();
return true;
}
QString HandlerOperator::operatorNameById(int operatorId) const
{
ObjectOperator *obj = m_operatorObjMap.value(operatorId);
if (!obj)
return QStringLiteral("?");
return obj->data().name;
}
std::vector<int> HandlerOperator::getExercisesForOperator(const QVector<Database::OpmOperatorExercise> &mapping, int operatorId)
{
std::vector<int> exercises;
for (const Database::OpmOperatorExercise &exMapping : mapping)
if (exMapping.operatorId == operatorId)
exercises.push_back(exMapping.exerciseId);
return exercises;
}
void HandlerOperator::onOperatorChangePasswordRequest(const rti::core::SampleIdentity &cookie,
const OperatorChangePasswordRequest &request)
{
DEBUG_LOG(m_logger) << "onOperatorChangePasswordRequest()";
ObjectOperator *ifs = m_operatorObjMap.value(request.id);
if (!ifs)
{
m_mainHandler->fts()->operatorChangePasswordReply(cookie,
Core::FunctionReplyObject(0, tr_lts("dds", "No valid operator id for changing password.")));
return;
}
Core::FunctionReplyObject ret;
Database::OpmOperator op = ifs->data();
const auto &pw = request.oldPassword;
const QByteArray ba(QByteArray::fromRawData(pw.c_str(), pw.size()));
const QString enteredPassword(QString::fromLatin1(QCryptographicHash::hash(ba, QCryptographicHash::Md5).toHex()));
const auto &pwNew = request.password;
const QByteArray baNew(QByteArray::fromRawData(pwNew.c_str(), pwNew.size()));
const QString enteredPasswordNew(QString::fromLatin1(QCryptographicHash::hash(baNew, QCryptographicHash::Md5).toHex()));
if (request.forceSet || op.password == enteredPassword)
{
if (enteredPassword == enteredPasswordNew)
ret = Core::FunctionReplyObject(0, tr_lts("dds", "Password is identical to old password."));
// else if (request.password().size() < n && $minimum1digit && minimum1extrachar && ...)
// {
// ret = Core::FunctionReplyObject(0, tr_lts("dds", "Password must be at least n characters"));
// }
else
{
op.password = enteredPasswordNew;
ret = ifs->updateObject(op);
}
}
else
{
ret = Core::FunctionReplyObject(0, tr_lts("dds", "Old password does not match."));
}
m_mainHandler->fts()->operatorChangePasswordReply(cookie, ret);
}
void HandlerOperator::onOperatorCreateModifyRequest(const rti::core::SampleIdentity &cookie,
const OperatorCreateModifyRequest &request)
{
Core::FunctionReplyObject ret;
DEBUG_LOG(m_logger) << "onOperatorCreateModifyRequest()";
if (!request.id.is_set())
ret = operatorCreateRequest(request);
else
ret = operatorModifyRequest(request);
if (ret.error())
WARNING_LOG(m_logger) << ret();
m_mainHandler->fts()->operatorCreateModifyReply(cookie, ret);
}
Core::FunctionReplyObject HandlerOperator::operatorCreateRequest(const OperatorCreateModifyRequest &request)
{
if (!request.name.is_set() ||
!request.password.is_set())
return Core::FunctionReplyObject(tr_lts("dds", "Can not create operator - name or password is empty."));
// Group anlegen
GroupCreateRequest groupRequest;
groupRequest.name = request.name.get();
groupRequest.description = request.description.get();
groupRequest.type = GroupType::OperatorGroup;
const Core::FunctionReplyObject groupRet = m_mainHandler->getHandlerGroup()->create(groupRequest);
if (groupRet.error())
return groupRet;
// Operator anlegen
Database::OpmOperator op;
op.name = QString::fromStdString(request.name.get());
if (request.description.is_set())
op.description = QString::fromStdString(request.description.get());
const auto &pw = request.password.get();
const QByteArray ba(QByteArray::fromRawData(pw.c_str(), pw.size()));
const QString enteredPassword(QString::fromLatin1(QCryptographicHash::hash(ba, QCryptographicHash::Md5).toHex()));
op.password = enteredPassword;
op.primaryGroupId = groupRet.id();
if (request.image.is_set())
op.image = LtsUtils::toQByteArray(request.image.get());
const auto vpbe = request.visiblePartiesByExercise;
for (const auto &pbe : vpbe)
{
if (!pbe.visibleParties.is_set() || pbe.exerciseId != 0) //has_value not support on windows yet so we need depricated is_set
continue;
op.visibleParties = LtsUtils::IntArray(pbe.visibleParties.get());
}
if (request.rolePresetId.is_set())
{
op.rolePresetId = request.rolePresetId.get();
}
op.projectionPriority = request.projectionPriority.is_set() ? request.projectionPriority.get() : 1;
op.audioChannelPriority = request.audioChannelPriority.is_set() ? request.audioChannelPriority.get() : 1;
ObjectOperator *ifs(new ObjectOperator(m_mainHandler));
const Core::FunctionReplyObject ret = ifs->createObject(op, {});
if (ret.error())
{
Core::RemoveElementRequest groupRemoveRequest(groupRet.id());
m_mainHandler->getHandlerGroup()->remove(groupRemoveRequest);
delete ifs;
return ret;
}
if (request.visibleExercises.is_set())
ifs->updateExercises(request.visibleExercises.get());
if (request.operatorRights.is_set())
{
GroupChangeMembersRequest grChReq;
grChReq.id = op.primaryGroupId;
grChReq.memberships = request.operatorRights.get();
// We don't actually care, if this fails...
m_mainHandler->getHandlerGroup()->changeMembership(grChReq);
ifs->reloadAcls(true);
}
m_operatorObjMap.insert(ifs->getId(), ifs);
return ret;
}
void HandlerOperator::operatorModifyRolePresetId( int operatorId, int rolePresetId)
{
DEBUG_LOG(m_logger)<< "HandlerOperator::operatorModifyRolePresetId"
<< " operatorId=" << operatorId
<< " rolePresetId=" << rolePresetId;
ObjectOperator *ifs = m_operatorObjMap.value(operatorId);
if (!ifs)
{
ERROR_LOG(m_logger)<< "No valid operator id given: "<< operatorId;
return;
}
Database::OpmOperator op = ifs->data();
op.rolePresetId = rolePresetId;
ifs->updateObject(op);
}
Core::FunctionReplyObject HandlerOperator::operatorModifyRequest(const OperatorCreateModifyRequest &request)
{
if (request.password.is_set())
return Core::FunctionReplyObject(tr_lts("dds", "Can not modify operator password with this function."));
ObjectOperator *ifs = m_operatorObjMap.value(request.id.get());
if (!ifs)
return Core::FunctionReplyObject(request.id.get(), tr_lts("dds", "No valid operator id given."));
Database::OpmOperator op = ifs->data();
if (request.name.is_set())
{
op.name = QString::fromStdString(request.name.get());
for (const ObjectOperator *o : qAsConst(m_operatorObjMap))
{
if (o == ifs)
continue;
if (o->name().compare(op.name, Qt::CaseInsensitive) == 0)
return Core::FunctionReplyObject(-1, tr_lts("dds", "Name '%1' already exists")).arg(op.name);
}
}
if (request.description.is_set())
op.description = QString::fromStdString(request.description.get());
if (request.image.is_set())
op.image = LtsUtils::toQByteArray(request.image.get());
const auto vpbe = request.visiblePartiesByExercise;
for (const auto &pbe : vpbe)
{
// only ex0 updated
if (!pbe.visibleParties.is_set() || pbe.exerciseId != 0) //has_value not support on windows yet so we need depricated is_set
continue;
op.visibleParties = LtsUtils::IntArray(pbe.visibleParties.get());
}
if (request.rolePresetId.is_set())
{
op.rolePresetId = request.rolePresetId.get();
}
if (request.visibleExercises.is_set())
ifs->updateExercises(request.visibleExercises.get());
if (request.projectionPriority.is_set())
op.projectionPriority = request.projectionPriority.get();
if (request.audioChannelPriority.is_set())
op.audioChannelPriority = request.audioChannelPriority.get();
op.properties = QString::fromStdString(request.properties);
return ifs->updateObject(op);
}
void HandlerOperator::onOperatorRemoveRequest(const rti::core::SampleIdentity &cookie,
const Core::RemoveElementRequest &request)
{
DEBUG_LOG(m_logger) << "onOperatorRemoveRequest()" << request;
ObjectOperator *ifs = m_operatorObjMap.value(request.id);
if (!ifs)
{
m_mainHandler->fts()->operatorRemoveReply(cookie,
Core::FunctionReplyObject(0, tr_lts("dds", "No valid operator id for deleting.")));
return;
}
if (!ifs->data().workstationId.isNull())
{
m_mainHandler->fts()->operatorRemoveReply(cookie,
Core::FunctionReplyObject(0, tr_lts("dds", "A logged in operator may not be deleted.")));
return;
}
OperatorManagement::User ddsData;
ddsData.id = request.id;
if (m_mainHandler->dds()->topicLockMaster()->isLocked(ddsData, 0))
{
m_mainHandler->fts()->operatorRemoveReply(cookie,
Core::FunctionReplyObject(request.id, tr_lts("dds", "Operator '%1' is used by another user!")).arg(ifs->name()));
return;
}
Core::RemoveElementRequest groupRemoveRequest(ifs->data().primaryGroupId);
Core::FunctionReplyObject ret = m_mainHandler->getHandlerGroup()->remove(groupRemoveRequest);
if (ret.error())
{
ERROR_LOG(m_logger) << ret();
}
else
{
ret = ifs->removeObject();
// Aus der lokalen Map löschen
m_operatorObjMap.remove(ifs->getId());
// und aus TopicLock entfernen
m_mainHandler->getHandlerLockedTopics()->operatorLoggedOut(ifs->getId());
delete ifs;
}
m_mainHandler->fts()->operatorRemoveReply(cookie, ret);
}
void HandlerOperator::onOperatorLoginRequest(const rti::core::SampleIdentity &cookie,
const OperatorLoginRequest &request)
{
DEBUG_LOG(m_logger) << "OperatorLoginRequest: " << request;
ObjectOperator *ifs = m_operatorObjMap.value(request.id);
if (!ifs)
{
m_mainHandler->fts()->operatorLoginReply(cookie,
Core::FunctionReplyObject(0, tr_lts("dds", "No operator found by the given id.")));
return;
}
const auto &pw = request.password;
const QByteArray ba(QByteArray::fromRawData(pw.c_str(), pw.size()));
const QString enteredPassword(QString::fromLatin1(QCryptographicHash::hash(ba, QCryptographicHash::Md5).toHex()));
if (enteredPassword != ifs->data().password)
{
m_mainHandler->fts()->operatorLoginReply(cookie,
Core::FunctionReplyObject(ifs->data().workstationId.toInt(), tr_lts("dds", "The password you have entered is invalid.")));
return;
}
// If no WS is claimed, just return operator ID
Core::FunctionReplyObject ret(ifs->data().id);
// Request claim a WS
if (!ifs->data().workstationId.isNull() && ifs->data().workstationId.toInt() > 0)
// operator already logged in
{
if (ifs->data().workstationId == request.workstationId)
{
// do nothing if same operator claims same workstation
}
else if (!request.force)
{
// Already claimed: Return WSid as ID
const auto ws = m_mainHandler->dds()->dtcAsm()->asset(ifs->data().workstationId.toInt());
ret = Core::FunctionReplyObject(ifs->data().workstationId.toInt(),
tr_lts("dds", "Operator already logged in on workstation %1.")).arg(QString::fromStdString(ws.name));
}
else
{
// force login, logout the other operator logged in on this WS, if there is any
int otherOperatorId = getLoggedOperatorId(ifs->data().workstationId.toInt());
if (otherOperatorId != 0 && otherOperatorId != ifs->data().id)
{
ObjectOperator *other = m_operatorObjMap.value(otherOperatorId);
if (other)
{
OperatorLogoutRequest req;
req.id = otherOperatorId;
onOperatorLogoutRequest(cookie, req);
}
}
Database::OpmOperator op = ifs->data();
op.workstationIp = request.workstationIp;
op.workstationId = request.workstationId;
ret = ifs->updateObject(op);
}
}
else
// operator not logged in on any workstation
{
// if other operator is logged in on same WS -> logout other operator and login our operator
int otherOperatorId = getLoggedOperatorId(request.workstationId);
if (otherOperatorId != 0 && otherOperatorId != ifs->data().id)
{
ObjectOperator *other = m_operatorObjMap.value(otherOperatorId);
if (other)
{
OperatorLogoutRequest req;
req.id = otherOperatorId;
onOperatorLogoutRequest(cookie, req);
WARNING_LOG(m_logger) << "Logged out operator " << otherOperatorId << " on workstation id " << request.workstationId;
}
}
// Claim WS:
Database::OpmOperator op = ifs->data();
op.workstationIp = request.workstationIp;
op.workstationId = request.workstationId;
ret = ifs->updateObject(op);
}
if (ret.error())
WARNING_LOG(m_logger) << ret();
else
{
m_mainHandler->getHandlerLockedTopics()->operatorLoggedIn(request.id, request.workstationId);
m_mainHandler->getHandlerActiveApps()->cleanupOperator(request.id);
}
m_mainHandler->fts()->operatorLoginReply(cookie, ret);
}
int HandlerOperator::getLoggedOperatorId(int workstationId) const
{
auto it = std::find_if(m_operatorObjMap.begin(), m_operatorObjMap.end(),
[workstationId](const ObjectOperator *oper) { return oper->data().workstationId == workstationId; });
return (it == m_operatorObjMap.end() ? 0 : it.value()->getId());
}
void HandlerOperator::onOperatorLogoutRequest(const rti::core::SampleIdentity &cookie,
const OperatorLogoutRequest &request)
{
DEBUG_LOG(m_logger) << "OperatorLogoutRequest: " << request;
ObjectOperator *ifs = m_operatorObjMap.value(request.id);
if (!ifs)
{
m_mainHandler->fts()->operatorLogoutReply(cookie, Core::FunctionReplyObject(0, tr_lts("dds", "No valid operator id for logout.")));
return;
}
if (ifs->data().workstationId.isNull() || ifs->data().workstationId == 0) // && ifs->data().workstationIp == 0 ?
{
m_mainHandler->fts()->operatorLogoutReply(cookie, Core::FunctionReplyObject(ifs->data().id));
return;
}
Database::OpmOperator op = ifs->data();
op.workstationIp = 0;
op.workstationId = QVariant();
m_mainHandler->getHandlerLockedTopics()->operatorLoggedOut(request.id); // workstationId = 0 -> logout
m_mainHandler->getHandlerActiveApps()->cleanupOperator(op.id);
m_mainHandler->fts()->operatorLogoutReply(cookie, ifs->updateObject(op));
}
void HandlerOperator::onOperatorGetSetSettingsRequest(const rti::core::SampleIdentity &cookie,
const OperatorGetSetSettingsRequest &request)
{
Core::FunctionReplyObject fro;
OperatorGetSetSettingsReply reply;
reply.id = request.id;
ObjectOperator *ifs = m_operatorObjMap.value(request.id);
if (ifs)
{
if (request.settings.is_set())
{
const auto &data = request.settings.get();
const QByteArray settings(QByteArray(reinterpret_cast<const char*>(&data[0]), data.size()));
if (!ifs->saveSettings(settings))
fro = Core::FunctionReplyObject(request.id, tr_lts("dds", "Error saving settings in database.") );
}
else
{
QByteArray settings;
if (!ifs->loadSettings(settings))
{
fro = Core::FunctionReplyObject(request.id, tr_lts("dds", "Error loading settings from database.") );
}
else
{
if (!settings.isEmpty())
{
reply.settings.set({});
reply.settings.get() = LtsUtils::convert<std::vector<uint8_t>>(settings);
}
}
}
}
else
{
fro = Core::FunctionReplyObject(request.id, tr_lts("dds", "No valid operator id for retrieving settings."));
}
if (fro.error())
{
reply.id = fro.id();
reply.errorString = fro.str();
reply.errorParams = fro.args();
}
m_mainHandler->fts()->operatorGetSetSettingsReply(cookie, reply);
}
void HandlerOperator::onOperatorApplyForeignAclsRequest(const rti::core::SampleIdentity &cookie, const OperatorApplyForeignAclsRequest &request)
{
DEBUG_LOG(m_logger) << "peratorApplyForeignAclsRequest: " << request;
auto reply = operatorApplyForeignAclsRequest(request);
if (reply.error())
WARNING_LOG(m_logger) << reply();
m_mainHandler->fts()->operatorApplyForeignAclsReply(cookie, reply);
}
Core::FunctionReplyObject HandlerOperator::operatorApplyForeignAclsRequest(const OperatorApplyForeignAclsRequest &request)
{
ObjectOperator *receiver = m_operatorObjMap.value(request.id);
if (!receiver)
return Core::FunctionReplyObject(0, tr_lts("dds", "Receiving operator not present."));
ObjectOperator *remoteOperator = m_operatorObjMap.value(request.remoteOperatorId);
if (!remoteOperator)
return Core::FunctionReplyObject(0, tr_lts("dds", "Remote operator not present."));
return receiver->setPrimaryGroupId(remoteOperator->data().primaryGroupId);
}
void HandlerOperator::onOperatorUpdateVisiblePartiesByExerciseRequest(const rti::core::SampleIdentity &cookie,
const OperatorUpdateVisiblePartiesByExerciseRequest &request)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << request;
// DEBUG_LOG(m_logger) << "onOperatorUpdateVisiblePartiesByExerciseRequest: " << request;
Core::FunctionReplyObject reply = operatorUpdateVisiblePartiesByExerciseRequest(request);
if (reply.error())
WARNING_LOG(m_logger) << reply();
m_mainHandler->fts()->operatorUpdateVisiblePartiesByExerciseReply(cookie, reply);
}
Core::FunctionReplyObject HandlerOperator::operatorUpdateVisiblePartiesByExerciseRequest(const OperatorUpdateVisiblePartiesByExerciseRequest &request)
{
ObjectOperator *ifs = m_operatorObjMap.value(request.id);
if (!ifs)
return Core::FunctionReplyObject(request.id, tr_lts("dds", "No valid operator id given."));
Database::OpmOperatorExercise opEx;
opEx.operatorId = request.id;
opEx.exerciseId = request.exerciseId;
std::vector<int> hiddenParties;
if (request.hiddenParties.is_set())
opEx.hiddenParties = LtsUtils::IntArray(request.hiddenParties.get());
if (request.visibleParties.is_set())
opEx.visibleParties = LtsUtils::IntArray(request.visibleParties.get());
opEx.properties = QString::fromStdString(request.properties);
return ifs->updateOperatorExercise(opEx);
}
void HandlerOperator::reloadAcls()
{
for (ObjectOperator *ifs : qAsConst(m_operatorObjMap))
ifs->reloadAcls();
}
void HandlerOperator::onOperatorWorkstationAliveChanged(const OperatorManagement::OperatorWorkstationAlive &data, DataModification modType)
{
INFO_LOG(m_logger) << "onOperatorWorkstationAliveChanged: " << data << ", " << modType;
if (data.operatorId < 0)
{
m_aliveData.remove(data.workstationId);
return;
}
auto &events = m_aliveData[data.workstationId];
events.push_back(data);
// do not store more than 30 history events
if (events.size() > 30)
events = events.mid(10);
}
void HandlerOperator::onCheckAliveTimeout()
{
if (m_aliveData.isEmpty())
return;
const qint64 tTimeoutTime = QDateTime::currentMSecsSinceEpoch() - 90 * 1000; // 90s
DEBUG_LOG(m_logger) << "onCheckAliveTimeout, timeoutTime: " << tTimeoutTime;
auto it = m_aliveData.begin();
while (it != m_aliveData.end())
{
DEBUG_LOG(m_logger) << "Checking alive for workstation " << it.key();
auto &events = it.value();
if (events.isEmpty() || events.last().lastAlive >= tTimeoutTime)
{
++it;
continue;
}
// no reference, will be a dangling one after m_aliveData.erase(it) !
const OperatorWorkstationAlive owa = events.last();
WARNING_LOG(m_logger) << "Timeout for workstation " << owa.workstationId
<< " and operator " << owa.operatorId << " - logging out";
if (m_logger.isDebugEnabled())
{
for (const auto &event : events)
DEBUG_LOG(m_logger) << "Alive history: " << event;
}
ObjectOperator *ifs = m_operatorObjMap.value(owa.operatorId);
it = m_aliveData.erase(it);
if (!ifs)
continue;
Database::OpmOperator op = ifs->data();
op.workstationIp = 0;
op.workstationId = QVariant();
m_mainHandler->getHandlerLockedTopics()->operatorLoggedOut(owa.operatorId); // workstationId = 0 -> logout
m_mainHandler->getHandlerActiveApps()->cleanupOperator(owa.operatorId);
ifs->updateObject(op);
}
}
} // Namespace OperatorManagement