diff --git a/src/services/gmail/gmailsynchronizer.cpp b/src/services/gmail/gmailsynchronizer.cpp index 78d8a00..63f5c55 100644 --- a/src/services/gmail/gmailsynchronizer.cpp +++ b/src/services/gmail/gmailsynchronizer.cpp @@ -10,6 +10,9 @@ #include #include #include +#include +#include "../core/events.h" +#include "../core/eventbus.h" GmailSynchronizer::GmailSynchronizer(QObject* parent) : Synchronizer(parent), @@ -41,6 +44,14 @@ bool GmailSynchronizer::initialize(const Account& account) return false; } + // Publish AccountConnectedEvent + WinoMail::Events::AccountConnectedEvent event; + event.eventId = QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" + QString::number(rand()); + event.timestamp = QDateTime::currentDateTimeUtc(); + event.accountId = account.id(); + event.provider = "gmail"; + PUBLISH(event); + qDebug() << "Gmail Synchronizer initialized for account:" << account.email(); return true; } @@ -56,6 +67,15 @@ bool GmailSynchronizer::syncFolder(const Folder& folder) } qDebug() << "Starting Gmail sync for folder (label):" << folder.name(); + + // Publish SyncStartedEvent + WinoMail::Events::SyncStartedEvent syncStartEvent; + syncStartEvent.eventId = QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" + QString::number(rand()); + syncStartEvent.timestamp = QDateTime::currentDateTimeUtc(); + syncStartEvent.accountId = m_account.id(); + syncStartEvent.folderId = QString::number(folder.id()); + PUBLISH(syncStartEvent); + emit folderSyncStarted(QString::number(folder.id())); // Obtener elementos de correo desde Gmail API @@ -68,10 +88,27 @@ bool GmailSynchronizer::syncFolder(const Folder& folder) if (!items.isEmpty()) { for (const MailItem& item : items) { emit mailItemAdded(item); + // Publish MailItemAddedEvent + WinoMail::Events::MailItemAddedEvent mailEvent; + mailEvent.eventId = QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" + QString::number(rand()); + mailEvent.timestamp = QDateTime::currentDateTimeUtc(); + mailEvent.item = item; + PUBLISH(mailEvent); } } emit folderSyncFinished(QString::number(folder.id()), true); + + // Publish SyncFinishedEvent + WinoMail::Events::SyncFinishedEvent syncFinishEvent; + syncFinishEvent.eventId = QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" + QString::number(rand()); + syncFinishEvent.timestamp = QDateTime::currentDateTimeUtc(); + syncFinishEvent.accountId = m_account.id(); + syncFinishEvent.folderId = QString::number(folder.id()); + syncFinishEvent.success = true; + syncFinishEvent.errorMessage = ""; + PUBLISH(syncFinishEvent); + return true; } @@ -154,6 +191,14 @@ bool GmailSynchronizer::appendMailItem(const QString& folderId, const MailItem& // Por ahora, simulamos éxito emit mailItemAdded(item); + + // Publish MailItemAddedEvent + WinoMail::Events::MailItemAddedEvent mailEvent; + mailEvent.eventId = QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" + QString::number(rand()); + mailEvent.timestamp = QDateTime::currentDateTimeUtc(); + mailEvent.item = item; + PUBLISH(mailEvent); + return true; } @@ -182,6 +227,14 @@ bool GmailSynchronizer::updateMailItemFlags(const QString& folderId, updatedItem.setFlagged(flagged); emit mailItemUpdated(updatedItem); + // Publish MailItemUpdatedEvent + WinoMail::Events::MailItemUpdatedEvent updateEvent; + updateEvent.eventId = QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" + QString::number(rand()); + updateEvent.timestamp = QDateTime::currentDateTimeUtc(); + updateEvent.item = updatedItem; + updateEvent.changedFields = QStringList() << "read" << "flagged"; // Simplified + PUBLISH(updateEvent); + return true; } @@ -202,6 +255,15 @@ bool GmailSynchronizer::deleteMailItem(const QString& folderId, // Por ahora, simulamos éxito emit mailItemRemoved(itemUid); + + // Publish MailItemRemovedEvent + WinoMail::Events::MailItemRemovedEvent removeEvent; + removeEvent.eventId = QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" + QString::number(rand()); + removeEvent.timestamp = QDateTime::currentDateTimeUtc(); + removeEvent.itemUid = itemUid; + removeEvent.folderId = folderId.toInt(); + PUBLISH(removeEvent); + return true; } diff --git a/src/services/outlook/outlooksynchronizer.cpp b/src/services/outlook/outlooksynchronizer.cpp index b684165..9dbda72 100644 --- a/src/services/outlook/outlooksynchronizer.cpp +++ b/src/services/outlook/outlooksynchronizer.cpp @@ -10,6 +10,9 @@ #include #include #include +#include +#include "../core/events.h" +#include "../core/eventbus.h" OutlookSynchronizer::OutlookSynchronizer(QObject* parent) : Synchronizer(parent), @@ -41,6 +44,14 @@ bool OutlookSynchronizer::initialize(const Account& account) return false; } + // Publish AccountConnectedEvent + WinoMail::Events::AccountConnectedEvent event; + event.eventId = QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" + QString::number(rand()); + event.timestamp = QDateTime::currentDateTimeUtc(); + event.accountId = account.id(); + event.provider = "outlook"; + PUBLISH(event); + qDebug() << "Outlook Synchronizer initialized for account:" << account.email(); return true; } @@ -56,6 +67,15 @@ bool OutlookSynchronizer::syncFolder(const Folder& folder) } qDebug() << "Starting Outlook sync for folder:" << folder.name(); + + // Publish SyncStartedEvent + WinoMail::Events::SyncStartedEvent syncStartEvent; + syncStartEvent.eventId = QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" + QString::number(rand()); + syncStartEvent.timestamp = QDateTime::currentDateTimeUtc(); + syncStartEvent.accountId = m_account.id(); + syncStartEvent.folderId = QString::number(folder.id()); + PUBLISH(syncStartEvent); + emit folderSyncStarted(QString::number(folder.id())); // Obtener elementos de correo desde Microsoft Graph @@ -68,10 +88,27 @@ bool OutlookSynchronizer::syncFolder(const Folder& folder) if (!items.isEmpty()) { for (const MailItem& item : items) { emit mailItemAdded(item); + // Publish MailItemAddedEvent + WinoMail::Events::MailItemAddedEvent mailEvent; + mailEvent.eventId = QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" + QString::number(rand()); + mailEvent.timestamp = QDateTime::currentDateTimeUtc(); + mailEvent.item = item; + PUBLISH(mailEvent); } } emit folderSyncFinished(QString::number(folder.id()), true); + + // Publish SyncFinishedEvent + WinoMail::Events::SyncFinishedEvent syncFinishEvent; + syncFinishEvent.eventId = QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" + QString::number(rand()); + syncFinishEvent.timestamp = QDateTime::currentDateTimeUtc(); + syncFinishEvent.accountId = m_account.id(); + syncFinishEvent.folderId = QString::number(folder.id()); + syncFinishEvent.success = true; + syncFinishEvent.errorMessage = ""; + PUBLISH(syncFinishEvent); + return true; } @@ -150,6 +187,14 @@ bool OutlookSynchronizer::appendMailItem(const QString& folderId, const MailItem // Por ahora, simulamos éxito emit mailItemAdded(item); + + // Publish MailItemAddedEvent + WinoMail::Events::MailItemAddedEvent mailEvent; + mailEvent.eventId = QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" + QString::number(rand()); + mailEvent.timestamp = QDateTime::currentDateTimeUtc(); + mailEvent.item = item; + PUBLISH(mailEvent); + return true; } @@ -178,6 +223,14 @@ bool OutlookSynchronizer::updateMailItemFlags(const QString& folderId, updatedItem.setFlagged(flagged); emit mailItemUpdated(updatedItem); + // Publish MailItemUpdatedEvent + WinoMail::Events::MailItemUpdatedEvent updateEvent; + updateEvent.eventId = QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" + QString::number(rand()); + updateEvent.timestamp = QDateTime::currentDateTimeUtc(); + updateEvent.item = updatedItem; + updateEvent.changedFields = QStringList() << "read" << "flagged"; // Simplified + PUBLISH(updateEvent); + return true; } @@ -198,6 +251,15 @@ bool OutlookSynchronizer::deleteMailItem(const QString& folderId, // Por ahora, simulamos éxito emit mailItemRemoved(itemUid); + + // Publish MailItemRemovedEvent + WinoMail::Events::MailItemRemovedEvent removeEvent; + removeEvent.eventId = QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" + QString::number(rand()); + removeEvent.timestamp = QDateTime::currentDateTimeUtc(); + removeEvent.itemUid = itemUid; + removeEvent.folderId = folderId.toInt(); + PUBLISH(removeEvent); + return true; } @@ -273,9 +335,66 @@ bool OutlookSynchronizer::refreshAccessToken() // En una implementación real, aquí usaríamos el refresh token // para obtener un nuevo access token desde Azure AD - qWarning() << "Token refresh not implemented - using stub"; - // Simulamos éxito por ahora - return !m_refreshToken.isEmpty(); + if (m_refreshToken.isEmpty()) { + qWarning() << "No refresh token available for Outlook"; + return false; + } + + // TODO: These should come from secure configuration, not hardcoded + const QString clientId = "YOUR_CLIENT_ID_HERE"; // Replace with actual client ID + const QString clientSecret = "YOUR_CLIENT_SECRET_HERE"; // Replace with actual client secret + const QString tokenUrl = "https://login.microsoftonline.com/common/oauth2/v2.0/token"; + + QNetworkRequest networkRequest{QUrl(tokenUrl)}; + networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + + QUrlQuery postData; + postData.addQueryItem("client_id", clientId); + postData.addQueryItem("scope", "Mail.Read Mail.ReadWrite Mail.Send offline_access"); + postData.addQueryItem("refresh_token", m_refreshToken); + postData.addQueryItem("grant_type", "refresh_token"); + postData.addQueryItem("client_secret", clientSecret); + + QNetworkReply* reply = m_networkManager->post(networkRequest, postData.toString(QUrl::FullyEncoded).toUtf8()); + + // Wait for reply synchronously for simplicity in this context + QEventLoop loop; + connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + loop.exec(); + + if (reply->error() != QNetworkReply::NoError) { + qWarning() << "Outlook token refresh failed:" << reply->errorString(); + reply->deleteLater(); + return false; + } + + QByteArray responseData = reply->readAll(); + reply->deleteLater(); + + QJsonParseError parseError; + QJsonDocument doc = QJsonDocument::fromJson(responseData, &parseError); + if (parseError.error != QJsonParseError::NoError) { + qWarning() << "Failed to parse Outlook token response:" << parseError.errorString(); + return false; + } + + QJsonObject obj = doc.object(); + if (!obj.contains("access_token")) { + qWarning() << "No access_token in Outlook token response"; + return false; + } + + m_accessToken = obj["access_token"].toString(); + int expiresIn = obj["expires_in"].toInt(3600); // default 1 hour + m_tokenExpires = QDateTime::currentDateTimeUtc().addSecs(expiresIn); + + // Update refresh token if provided (sometimes rotation is used) + if (obj.contains("refresh_token")) { + m_refreshToken = obj["refresh_token"].toString(); + } + + qDebug() << "Outlook access token refreshed successfully, expires in" << expiresIn << "seconds"; + return true; } QString OutlookSynchronizer::getDeltaLink(const QString& folderId) const