removed oauth and using token instead
This commit is contained in:
parent
7a30f648a5
commit
9e3d418498
@ -49,40 +49,16 @@ void IntegrationPluginTempo::startPairing(ThingPairingInfo *info)
|
|||||||
|
|
||||||
if (info->thingClassId() == tempoConnectionThingClassId) {
|
if (info->thingClassId() == tempoConnectionThingClassId) {
|
||||||
|
|
||||||
QByteArray clientId = configValue(tempoPluginCustomClientIdParamTypeId).toByteArray();
|
|
||||||
QByteArray clientSecret = configValue(tempoPluginCustomClientSecretParamTypeId).toByteArray();
|
|
||||||
if (clientId.isEmpty() || clientSecret.isEmpty()) {
|
|
||||||
clientId = apiKeyStorage()->requestKey("tempo").data("clientId");
|
|
||||||
clientSecret = apiKeyStorage()->requestKey("tempo").data("clientSecret");
|
|
||||||
} else {
|
|
||||||
qCDebug(dcTempo()) << "Using custom client secret and id";
|
|
||||||
}
|
|
||||||
if (clientId.isEmpty() || clientSecret.isEmpty()) {
|
|
||||||
info->finish(Thing::ThingErrorAuthenticationFailure, tr("Client id and/or seceret is not available."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString jiraCloudInstanceName = info->params().paramValue(tempoConnectionThingAtlassianAccountNameParamTypeId).toString();
|
QString jiraCloudInstanceName = info->params().paramValue(tempoConnectionThingAtlassianAccountNameParamTypeId).toString();
|
||||||
Tempo *tempo = new Tempo(hardwareManager()->networkManager(), clientId, clientSecret, this);
|
|
||||||
|
|
||||||
QUrl url = tempo->getLoginUrl(QUrl("https://127.0.0.1:8888"), jiraCloudInstanceName);
|
|
||||||
qCDebug(dcTempo()) << "Checking if the Tempo server is reachable: https://api.tempo.io/core/3";
|
qCDebug(dcTempo()) << "Checking if the Tempo server is reachable: https://api.tempo.io/core/3";
|
||||||
QNetworkReply *reply = hardwareManager()->networkManager()->get(QNetworkRequest(QUrl("https://api.tempo.io/core/3")));
|
QNetworkReply *reply = hardwareManager()->networkManager()->get(QNetworkRequest(QUrl("https://api.tempo.io/core/3")));
|
||||||
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
||||||
connect(reply, &QNetworkReply::finished, info, [reply, info, tempo, url, this] {
|
connect(reply, &QNetworkReply::finished, info, [reply, info, this] {
|
||||||
|
|
||||||
if (reply->error() != QNetworkReply::NetworkError::HostNotFoundError) {
|
if (reply->error() != QNetworkReply::NetworkError::HostNotFoundError) {
|
||||||
qCDebug(dcTempo()) << "Tempo server is reachable";
|
qCDebug(dcTempo()) << "Tempo server is reachable";
|
||||||
ThingId thingId = info->thingId();
|
|
||||||
m_setupTempoConnections.insert(info->thingId(), tempo);
|
|
||||||
connect(info, &ThingPairingInfo::aborted, this, [thingId, this] {
|
|
||||||
qCWarning(dcTempo()) << "ThingPairingInfo aborted, cleaning up";
|
|
||||||
Tempo *tempo = m_setupTempoConnections.take(thingId);
|
|
||||||
if (tempo)
|
|
||||||
tempo->deleteLater();
|
|
||||||
});
|
|
||||||
qCDebug(dcTempo()) << "OAuthUrl" << url.toString();
|
|
||||||
info->setOAuthUrl(url);
|
|
||||||
info->finish(Thing::ThingErrorNoError);
|
info->finish(Thing::ThingErrorNoError);
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcTempo()) << "Got online check error" << reply->error() << reply->errorString();
|
qCWarning(dcTempo()) << "Got online check error" << reply->error() << reply->errorString();
|
||||||
@ -101,36 +77,61 @@ void IntegrationPluginTempo::confirmPairing(ThingPairingInfo *info, const QStrin
|
|||||||
|
|
||||||
if (info->thingClassId() == tempoConnectionThingClassId) {
|
if (info->thingClassId() == tempoConnectionThingClassId) {
|
||||||
qCDebug(dcTempo()) << "Confirm pairing" << info->thingName();
|
qCDebug(dcTempo()) << "Confirm pairing" << info->thingName();
|
||||||
QUrl url(secret);
|
if (secret.isEmpty()) {
|
||||||
QUrlQuery query(url);
|
|
||||||
QByteArray authorizationCode = query.queryItemValue("code").toLocal8Bit();
|
|
||||||
if (authorizationCode.isEmpty()) {
|
|
||||||
qCWarning(dcTempo()) << "No authorization code received.";
|
qCWarning(dcTempo()) << "No authorization code received.";
|
||||||
return info->finish(Thing::ThingErrorAuthenticationFailure);
|
return info->finish(Thing::ThingErrorAuthenticationFailure);
|
||||||
}
|
}
|
||||||
|
QString atlassianAccountName = info->params().paramValue(tempoConnectionThingAtlassianAccountNameParamTypeId).toString();
|
||||||
Tempo *tempo = m_setupTempoConnections.value(info->thingId());
|
Tempo *tempo = new Tempo(hardwareManager()->networkManager(), atlassianAccountName, secret, this);
|
||||||
if (!tempo) {
|
tempo->getAccounts();
|
||||||
qWarning(dcTempo()) << "No tempo connection found for device:" << info->thingName();
|
connect(info, &ThingPairingInfo::aborted, tempo, &Tempo::deleteLater);
|
||||||
m_setupTempoConnections.remove(info->thingId());
|
connect(tempo, &Tempo::authenticationStatusChanged, info, [info, tempo, this] (bool authenticated){
|
||||||
return info->finish(Thing::ThingErrorHardwareFailure);
|
if (authenticated) {
|
||||||
}
|
m_setupTempoConnections.insert(info->thingId(), tempo);
|
||||||
qCDebug(dcTempo()) << "Authorization code" << authorizationCode.mid(0, 4)+QString().fill('*', authorizationCode.length()-4) ;
|
info->finish(Thing::ThingErrorNoError);
|
||||||
tempo->getAccessTokenFromAuthorizationCode(authorizationCode);
|
}
|
||||||
connect(tempo, &Tempo::receivedRefreshToken, info, [info, this](const QByteArray &refreshToken){
|
|
||||||
qCDebug(dcTempo()) << "Token:" << refreshToken.mid(0, 4)+QString().fill('*', refreshToken.length()-4) ;
|
|
||||||
|
|
||||||
pluginStorage()->beginGroup(info->thingId().toString());
|
|
||||||
pluginStorage()->setValue("refresh_token", refreshToken);
|
|
||||||
pluginStorage()->endGroup();
|
|
||||||
|
|
||||||
info->finish(Thing::ThingErrorNoError);
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Q_ASSERT_X(false, "confirmPairing", QString("Unhandled thingClassId: %1").arg(info->thingClassId().toString()).toUtf8());
|
Q_ASSERT_X(false, "confirmPairing", QString("Unhandled thingClassId: %1").arg(info->thingClassId().toString()).toUtf8());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IntegrationPluginTempo::discoverThings(ThingDiscoveryInfo *info)
|
||||||
|
{
|
||||||
|
qCDebug(dcTempo()) << "Discover things";
|
||||||
|
if (info->thingClassId() == accountThingClassId) {
|
||||||
|
Q_FOREACH(Tempo *tempo, m_tempoConnections) {
|
||||||
|
tempo->getAccounts();
|
||||||
|
Thing *parentThing = m_tempoConnections.key(tempo);
|
||||||
|
if (!parentThing) {
|
||||||
|
qCWarning(dcTempo()) << "Parent not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
connect(tempo, &Tempo::accountsReceived, info, [info, parentThing, this, tempo] (const QList<Tempo::Account> &accounts) {
|
||||||
|
Q_FOREACH(Tempo::Account account, accounts) {
|
||||||
|
ThingDescriptor descriptor(accountThingClassId, account.name, account.customer.name, parentThing->id());
|
||||||
|
ParamList params;
|
||||||
|
params << Param(accountThingKeyParamTypeId, account.key);
|
||||||
|
descriptor.setParams(params);
|
||||||
|
info->addThingDescriptor(descriptor);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (info->thingClassId() == teamThingClassId) {
|
||||||
|
Q_FOREACH(Tempo *tempo, m_tempoConnections) {
|
||||||
|
tempo->getTeams();
|
||||||
|
Thing *parentThing = m_tempoConnections.key(tempo);
|
||||||
|
if (!parentThing) {
|
||||||
|
qCWarning(dcTempo()) << "Parent not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QTimer::singleShot(5000, info, [info] {
|
||||||
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void IntegrationPluginTempo::setupThing(ThingSetupInfo *info)
|
void IntegrationPluginTempo::setupThing(ThingSetupInfo *info)
|
||||||
{
|
{
|
||||||
Thing *thing = info->thing();
|
Thing *thing = info->thing();
|
||||||
@ -155,37 +156,30 @@ void IntegrationPluginTempo::setupThing(ThingSetupInfo *info)
|
|||||||
} else {
|
} else {
|
||||||
//device loaded from the device database, needs a new access token;
|
//device loaded from the device database, needs a new access token;
|
||||||
pluginStorage()->beginGroup(thing->id().toString());
|
pluginStorage()->beginGroup(thing->id().toString());
|
||||||
QByteArray refreshToken = pluginStorage()->value("refresh_token").toByteArray();
|
QByteArray token = pluginStorage()->value("token").toByteArray();
|
||||||
pluginStorage()->endGroup();
|
pluginStorage()->endGroup();
|
||||||
if (refreshToken.isEmpty()) {
|
if (token.isEmpty()) {
|
||||||
info->finish(Thing::ThingErrorAuthenticationFailure, tr("Refresh token is not available."));
|
info->finish(Thing::ThingErrorAuthenticationFailure, tr("Token is not available."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
QString jiraInstanceName = thing->paramValue(tempoConnectionThingAtlassianAccountNameParamTypeId).toString();
|
||||||
|
Tempo *tempo = new Tempo(hardwareManager()->networkManager(), jiraInstanceName, token, this);
|
||||||
|
tempo->getAccounts();
|
||||||
|
|
||||||
QByteArray clientId = configValue(tempoPluginCustomClientIdParamTypeId).toByteArray();
|
|
||||||
QByteArray clientSecret = configValue(tempoPluginCustomClientSecretParamTypeId).toByteArray();
|
|
||||||
if (clientId.isEmpty() || clientSecret.isEmpty()) {
|
|
||||||
clientId = apiKeyStorage()->requestKey("tempo").data("clientId");
|
|
||||||
clientSecret = apiKeyStorage()->requestKey("tempo").data("clientSecret");
|
|
||||||
} else {
|
|
||||||
qCDebug(dcTempo()) << "Using custom API id and secret.";
|
|
||||||
}
|
|
||||||
if (clientId.isEmpty() || clientSecret.isEmpty()) {
|
|
||||||
info->finish(Thing::ThingErrorAuthenticationFailure, tr("Client id and/or secret is not available."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Tempo *tempo = new Tempo(hardwareManager()->networkManager(), clientId, clientSecret, this);
|
|
||||||
tempo->getAccessTokenFromRefreshToken(refreshToken);
|
|
||||||
connect(tempo, &Tempo::receivedAccessToken, info, [info] {
|
|
||||||
info->finish(Thing::ThingErrorNoError);
|
|
||||||
});
|
|
||||||
connect(info, &ThingSetupInfo::aborted, tempo, &Tempo::deleteLater);
|
connect(info, &ThingSetupInfo::aborted, tempo, &Tempo::deleteLater);
|
||||||
|
connect(tempo, &Tempo::authenticationStatusChanged, info, [info, tempo, this] (bool authenticated){
|
||||||
|
if (authenticated) {
|
||||||
|
m_tempoConnections.insert(info->thing(), tempo);
|
||||||
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
connect(tempo, &Tempo::connectionChanged, this, &IntegrationPluginTempo::onConnectionChanged);
|
connect(tempo, &Tempo::connectionChanged, this, &IntegrationPluginTempo::onConnectionChanged);
|
||||||
connect(tempo, &Tempo::authenticationStatusChanged, this, &IntegrationPluginTempo::onAuthenticationStatusChanged);
|
connect(tempo, &Tempo::authenticationStatusChanged, this, &IntegrationPluginTempo::onAuthenticationStatusChanged);
|
||||||
connect(tempo, &Tempo::accountsReceived, this, &IntegrationPluginTempo::onReceivedAccounts);
|
connect(tempo, &Tempo::accountsReceived, this, &IntegrationPluginTempo::onReceivedAccounts);
|
||||||
|
|
||||||
} else if (thing->thingClassId() == accountThingClassId) {
|
} else if (thing->thingClassId() == accountThingClassId ||
|
||||||
|
thing->thingClassId() == teamThingClassId){
|
||||||
Thing *parentThing = myThings().findById(thing->parentId());
|
Thing *parentThing = myThings().findById(thing->parentId());
|
||||||
if (parentThing->setupComplete()) {
|
if (parentThing->setupComplete()) {
|
||||||
info->finish(Thing::ThingErrorNoError);
|
info->finish(Thing::ThingErrorNoError);
|
||||||
@ -231,6 +225,8 @@ void IntegrationPluginTempo::postSetupThing(Thing *thing)
|
|||||||
|
|
||||||
} else if (thing->thingClassId() == accountThingClassId) {
|
} else if (thing->thingClassId() == accountThingClassId) {
|
||||||
|
|
||||||
|
} else if (thing->thingClassId() == teamThingClassId) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,46 +272,12 @@ void IntegrationPluginTempo::onAuthenticationStatusChanged(bool authenticated)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
thing->setStateValue(tempoConnectionLoggedInStateTypeId, authenticated);
|
thing->setStateValue(tempoConnectionLoggedInStateTypeId, authenticated);
|
||||||
if (!authenticated) {
|
|
||||||
//refresh access token needs to be refreshed
|
|
||||||
pluginStorage()->beginGroup(thing->id().toString());
|
|
||||||
QByteArray refreshToken = pluginStorage()->value("refresh_token").toByteArray();
|
|
||||||
pluginStorage()->endGroup();
|
|
||||||
tempoConnection->getAccessTokenFromRefreshToken(refreshToken);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void IntegrationPluginTempo::onReceivedAccounts(const QList<Tempo::Account> &accounts)
|
void IntegrationPluginTempo::onReceivedAccounts(const QList<Tempo::Account> &accounts)
|
||||||
{
|
{
|
||||||
qCDebug(dcTempo()) << "Received" << accounts.count() << "accounts";
|
qCDebug(dcTempo()) << "Received" << accounts.count() << "accounts";
|
||||||
|
|
||||||
Tempo *tempoConnection = static_cast<Tempo *>(sender());
|
|
||||||
Thing *parentThing = m_tempoConnections.key(tempoConnection);
|
|
||||||
if (!parentThing)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ThingDescriptors desciptors;
|
|
||||||
Q_FOREACH(Tempo::Account account, accounts) {
|
|
||||||
ThingClassId thingClassId;
|
|
||||||
|
|
||||||
//Thing * existingThing = myThings().findByParams(ParamList() << Param(m_idParamTypeIds.value(thingClassId), appliance.homeApplianceId));
|
|
||||||
//if (existingThing) {
|
|
||||||
// qCDebug(dcTempo()) << "Thing is already added to system" << existingThing->name();
|
|
||||||
//Set connected state;
|
|
||||||
//existingThing->setStateValue(m_connectedStateTypeIds.value(thingClassId), appliance.connected);
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
qCDebug(dcTempo()) << "Found new account:" << account.name << "key:" << account.key << "id:" << account.id;
|
|
||||||
ThingDescriptor descriptor(thingClassId, account.name, account.key, parentThing->id());
|
|
||||||
|
|
||||||
ParamList params;
|
|
||||||
//params << Param(m_idParamTypeIds.value(thingClassId), appliance.homeApplianceId);
|
|
||||||
descriptor.setParams(params);
|
|
||||||
desciptors.append(descriptor);
|
|
||||||
}
|
|
||||||
if (!desciptors.isEmpty())
|
|
||||||
emit autoThingsAppeared(desciptors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginTempo::onAccountWorkloadReceived(const QString &accountKey, QList<Tempo::Worklog> workloads)
|
void IntegrationPluginTempo::onAccountWorkloadReceived(const QString &accountKey, QList<Tempo::Worklog> workloads)
|
||||||
|
|||||||
@ -49,6 +49,7 @@ public:
|
|||||||
void startPairing(ThingPairingInfo *info) override;
|
void startPairing(ThingPairingInfo *info) override;
|
||||||
void confirmPairing(ThingPairingInfo *info, const QString &username, const QString &secret) override;
|
void confirmPairing(ThingPairingInfo *info, const QString &username, const QString &secret) override;
|
||||||
|
|
||||||
|
void discoverThings(ThingDiscoveryInfo *info) override;
|
||||||
void setupThing(ThingSetupInfo *info) override;
|
void setupThing(ThingSetupInfo *info) override;
|
||||||
void postSetupThing(Thing *thing) override;
|
void postSetupThing(Thing *thing) override;
|
||||||
void executeAction(ThingActionInfo *info) override;
|
void executeAction(ThingActionInfo *info) override;
|
||||||
|
|||||||
@ -2,23 +2,6 @@
|
|||||||
"id": "809bc4ca-d1cd-4279-9e0d-7324537ccb5a",
|
"id": "809bc4ca-d1cd-4279-9e0d-7324537ccb5a",
|
||||||
"name": "tempo",
|
"name": "tempo",
|
||||||
"displayName": "Tempo",
|
"displayName": "Tempo",
|
||||||
"apiKeys": ["tempo"],
|
|
||||||
"paramTypes": [
|
|
||||||
{
|
|
||||||
"id": "c130b2b7-6d30-406e-899b-669a065daee3",
|
|
||||||
"name": "customClientId",
|
|
||||||
"displayName": "Custom client id",
|
|
||||||
"defaultValue": "",
|
|
||||||
"type": "QString"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "9c759711-e772-44ce-9d86-6a3af89c2d94",
|
|
||||||
"name": "customClientSecret",
|
|
||||||
"displayName": "Custom client secret",
|
|
||||||
"defaultValue": "",
|
|
||||||
"type": "QString"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"vendors": [
|
"vendors": [
|
||||||
{
|
{
|
||||||
"id": "58fc1ab7-b8b5-4e52-8388-72957ce5852d",
|
"id": "58fc1ab7-b8b5-4e52-8388-72957ce5852d",
|
||||||
@ -31,7 +14,7 @@
|
|||||||
"displayName": "Tempo connection",
|
"displayName": "Tempo connection",
|
||||||
"interfaces": ["account"],
|
"interfaces": ["account"],
|
||||||
"createMethods": ["user"],
|
"createMethods": ["user"],
|
||||||
"setupMethod": "oauth",
|
"setupMethod": "displayPin",
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "b4110c37-8331-4057-8e9f-12f34c2623fe",
|
"id": "b4110c37-8331-4057-8e9f-12f34c2623fe",
|
||||||
@ -82,7 +65,7 @@
|
|||||||
"name": "account",
|
"name": "account",
|
||||||
"displayName": "Account",
|
"displayName": "Account",
|
||||||
"interfaces": ["connectable"],
|
"interfaces": ["connectable"],
|
||||||
"createMethods": ["auto"],
|
"createMethods": ["discovery"],
|
||||||
"browsable": true,
|
"browsable": true,
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
@ -183,6 +166,34 @@
|
|||||||
"unit": "Minutes"
|
"unit": "Minutes"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "11c85176-e7fe-44b4-995a-24757273f3af",
|
||||||
|
"name": "team",
|
||||||
|
"displayName": "Team",
|
||||||
|
"interfaces": ["connectable"],
|
||||||
|
"createMethods": ["discovery"],
|
||||||
|
"browsable": true,
|
||||||
|
"paramTypes": [
|
||||||
|
{
|
||||||
|
"id": "bb90e986-fcfa-47e8-8783-f2b5a887314a",
|
||||||
|
"name": "key",
|
||||||
|
"displayName": "Key",
|
||||||
|
"defaultValue": "",
|
||||||
|
"type": "QString"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateTypes": [
|
||||||
|
{
|
||||||
|
"id": "a125d3b5-676f-49eb-bb93-feae233c2e91",
|
||||||
|
"name": "connected",
|
||||||
|
"displayName": "Connected",
|
||||||
|
"displayNameEvent": "Connected changed",
|
||||||
|
"defaultValue": true,
|
||||||
|
"cached": false,
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
176
tempo/tempo.cpp
176
tempo/tempo.cpp
@ -34,158 +34,61 @@
|
|||||||
#include "tempo.h"
|
#include "tempo.h"
|
||||||
#include "extern-plugininfo.h"
|
#include "extern-plugininfo.h"
|
||||||
|
|
||||||
Tempo::Tempo(NetworkAccessManager *networkmanager, const QByteArray &clientId, const QByteArray &clientSecret, QObject *parent) :
|
Tempo::Tempo(NetworkAccessManager *networkmanager, const QString &jiraCloudInstanceName, const QString &token, QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
m_clientId(clientId),
|
m_token(token),
|
||||||
m_clientSecret(clientSecret),
|
m_jiraCloudInstanceName(jiraCloudInstanceName),
|
||||||
m_networkManager(networkmanager)
|
m_networkManager(networkmanager)
|
||||||
|
|
||||||
{
|
{
|
||||||
m_tokenRefreshTimer = new QTimer(this);
|
qCDebug(dcTempo()) << "Creating tempo connection to" << m_jiraCloudInstanceName;
|
||||||
m_tokenRefreshTimer->setSingleShot(true);
|
|
||||||
connect(m_tokenRefreshTimer, &QTimer::timeout, this, &Tempo::onRefreshTimer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray Tempo::accessToken()
|
Tempo::~Tempo()
|
||||||
{
|
{
|
||||||
return m_accessToken;
|
qCDebug(dcTempo()) << "Deleting tempo connection to" << m_jiraCloudInstanceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray Tempo::refreshToken()
|
QString Tempo::token() const
|
||||||
{
|
{
|
||||||
return m_refreshToken;
|
return m_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
QUrl Tempo::getLoginUrl(const QUrl &redirectUrl, const QString &jiraCloudInstanceName)
|
void Tempo::getTeams()
|
||||||
{
|
{
|
||||||
if (m_clientId.isEmpty()) {
|
QUrl url = QUrl(m_baseControlUrl+"/teams");
|
||||||
qWarning(dcTempo) << "Client Id not defined!";
|
qCDebug(dcTempo()) << "Get teams, url" << url.toString();
|
||||||
return QUrl("");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (redirectUrl.isEmpty()){
|
|
||||||
qWarning(dcTempo) << "No redirect uri defined!";
|
|
||||||
}
|
|
||||||
m_redirectUri = QUrl::toPercentEncoding(redirectUrl.toString());
|
|
||||||
|
|
||||||
QUrl url;
|
|
||||||
url.setScheme("https");
|
|
||||||
url.setHost(jiraCloudInstanceName+".atlassian.net");
|
|
||||||
url.setPath("/plugins/servlet/ac/io.tempo.jira/oauth-authorize/");
|
|
||||||
QUrlQuery query;
|
|
||||||
query.addQueryItem("client_id", m_clientId);
|
|
||||||
query.addQueryItem("redirect_uri", m_redirectUri);
|
|
||||||
query.addQueryItem("access_type", "tenant_user");
|
|
||||||
url.setQuery(query);
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Tempo::getAccessTokenFromRefreshToken(const QByteArray &refreshToken)
|
|
||||||
{
|
|
||||||
if (refreshToken.isEmpty()) {
|
|
||||||
qWarning(dcTempo) << "No refresh token given!";
|
|
||||||
setAuthenticated(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QUrl url(m_baseTokenUrl);
|
|
||||||
QUrlQuery query;
|
|
||||||
query.clear();
|
|
||||||
query.addQueryItem("grant_type", "refresh_token");
|
|
||||||
query.addQueryItem("refresh_token", refreshToken);
|
|
||||||
query.addQueryItem("client_secret", m_clientSecret);
|
|
||||||
|
|
||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
request.setRawHeader("Authorization", "Bearer "+m_token.toUtf8());
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, query.toString().toUtf8());
|
QNetworkReply *reply = m_networkManager->get(request);
|
||||||
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
||||||
connect(reply, &QNetworkReply::finished, this, [this, reply](){
|
connect(reply, &QNetworkReply::finished, this, [this, reply]{
|
||||||
|
|
||||||
QByteArray rawData = reply->readAll();
|
QByteArray rawData = reply->readAll();
|
||||||
if (!checkStatusCode(reply, rawData)) {
|
if (!checkStatusCode(reply, rawData)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QJsonDocument data = QJsonDocument::fromJson(rawData);
|
QVariantMap dataMap = QJsonDocument::fromJson(rawData).toVariant().toMap();
|
||||||
|
QVariantList teamList = dataMap.value("results").toList();
|
||||||
|
QList<Team> teams;
|
||||||
|
Q_FOREACH(QVariant var, teamList) {
|
||||||
|
QVariantMap map = var.toMap();
|
||||||
|
Team team;
|
||||||
|
team.self = map["self"].toString();
|
||||||
|
team.id = map["id"].toInt();
|
||||||
|
team.name = map["name"].toString();
|
||||||
|
team.summary = map["summery"].toString();
|
||||||
|
|
||||||
if(!data.toVariant().toMap().contains("access_token")) {
|
QVariantMap lead = map["lead"].toMap();
|
||||||
setAuthenticated(false);
|
team.lead.self = lead["self"].toString();
|
||||||
return;
|
team.lead.accountId = lead["accountId"].toString();
|
||||||
|
team.lead.displayName = lead["displayName"].toString();
|
||||||
|
|
||||||
|
teams.append(team);
|
||||||
}
|
}
|
||||||
m_accessToken = data.toVariant().toMap().value("access_token").toByteArray();
|
if (!teams.isEmpty()) {
|
||||||
emit receivedAccessToken(m_accessToken);
|
emit teamsReceived(teams);
|
||||||
|
|
||||||
if (data.toVariant().toMap().contains("expires_in")) {
|
|
||||||
int expireTime = data.toVariant().toMap().value("expires_in").toInt();
|
|
||||||
qCDebug(dcTempo) << "Access token expires int" << expireTime << "s, at" << QDateTime::currentDateTime().addSecs(expireTime).toString();
|
|
||||||
if (!m_tokenRefreshTimer) {
|
|
||||||
qWarning(dcTempo()) << "Access token refresh timer not initialized";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (expireTime < 20) {
|
|
||||||
qCWarning(dcTempo()) << "Expire time too short";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_tokenRefreshTimer->start((expireTime - 20) * 1000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Tempo::getAccessTokenFromAuthorizationCode(const QByteArray &authorizationCode)
|
|
||||||
{
|
|
||||||
// Obtaining access token
|
|
||||||
if(authorizationCode.isEmpty())
|
|
||||||
qWarning(dcTempo()) << "No authorization code given!";
|
|
||||||
if(m_clientId.isEmpty())
|
|
||||||
qWarning(dcTempo()) << "Client key not set!";
|
|
||||||
if(m_clientSecret.isEmpty())
|
|
||||||
qWarning(dcTempo()) << "Client secret not set!";
|
|
||||||
|
|
||||||
QUrl url = QUrl(m_baseTokenUrl);
|
|
||||||
QUrlQuery query; url.setQuery(query);
|
|
||||||
|
|
||||||
query.clear();
|
|
||||||
query.addQueryItem("client_id", m_clientId);
|
|
||||||
query.addQueryItem("client_secret", m_clientSecret);
|
|
||||||
query.addQueryItem("redirect_uri", m_redirectUri);
|
|
||||||
query.addQueryItem("grant_type", "authorization_code");
|
|
||||||
query.addQueryItem("code", authorizationCode);
|
|
||||||
// query.addQueryItem("code_verifier", m_codeChallenge);
|
|
||||||
|
|
||||||
QNetworkRequest request(url);
|
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, query.toString().toUtf8());
|
|
||||||
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
|
||||||
connect(reply, &QNetworkReply::finished, this, [this, reply](){
|
|
||||||
|
|
||||||
QByteArray rawData = reply->readAll();
|
|
||||||
if (!checkStatusCode(reply, rawData)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(rawData);
|
|
||||||
if(!jsonDoc.toVariant().toMap().contains("access_token") || !jsonDoc.toVariant().toMap().contains("refresh_token") ) {
|
|
||||||
setAuthenticated(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_accessToken = jsonDoc.toVariant().toMap().value("access_token").toByteArray();
|
|
||||||
receivedAccessToken(m_accessToken);
|
|
||||||
m_refreshToken = jsonDoc.toVariant().toMap().value("refresh_token").toByteArray();
|
|
||||||
receivedRefreshToken(m_refreshToken);
|
|
||||||
|
|
||||||
if (jsonDoc.toVariant().toMap().contains("expires_in")) {
|
|
||||||
int expireTime = jsonDoc.toVariant().toMap().value("expires_in").toInt();
|
|
||||||
qCDebug(dcTempo()) << "Token expires in" << expireTime << "s, at" << QDateTime::currentDateTime().addSecs(expireTime).toString();
|
|
||||||
if (!m_tokenRefreshTimer) {
|
|
||||||
qWarning(dcTempo()) << "Token refresh timer not initialized";
|
|
||||||
setAuthenticated(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (expireTime < 20) {
|
|
||||||
qCWarning(dcTempo()) << "Expire time too short";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_tokenRefreshTimer->start((expireTime - 20) * 1000);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -193,9 +96,10 @@ void Tempo::getAccessTokenFromAuthorizationCode(const QByteArray &authorizationC
|
|||||||
void Tempo::getAccounts()
|
void Tempo::getAccounts()
|
||||||
{
|
{
|
||||||
QUrl url = QUrl(m_baseControlUrl+"/accounts");
|
QUrl url = QUrl(m_baseControlUrl+"/accounts");
|
||||||
|
qCDebug(dcTempo()) << "Get accounts. Url" << url.toString();
|
||||||
|
|
||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
request.setRawHeader("Authorization", "Bearer "+m_accessToken);
|
request.setRawHeader("Authorization", "Bearer "+m_token.toUtf8());
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->get(request);
|
QNetworkReply *reply = m_networkManager->get(request);
|
||||||
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
||||||
@ -243,7 +147,7 @@ void Tempo::getAccounts()
|
|||||||
accounts.append(account);
|
accounts.append(account);
|
||||||
}
|
}
|
||||||
if (!accounts.isEmpty()) {
|
if (!accounts.isEmpty()) {
|
||||||
|
emit accountsReceived(accounts);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -256,8 +160,10 @@ void Tempo::getWorkloadByAccount(const QString &accountKey, QDate from, QDate to
|
|||||||
query.addQueryItem("to", to.toString(Qt::DateFormat::ISODate));
|
query.addQueryItem("to", to.toString(Qt::DateFormat::ISODate));
|
||||||
url.setQuery(query);
|
url.setQuery(query);
|
||||||
|
|
||||||
|
qCDebug(dcTempo()) << "Get workload by account. Url" << url.toString();
|
||||||
|
|
||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
request.setRawHeader("Authorization", "Bearer "+m_accessToken);
|
request.setRawHeader("Authorization", "Bearer "+m_token.toUtf8());
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkManager->get(request);
|
QNetworkReply *reply = m_networkManager->get(request);
|
||||||
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
||||||
@ -292,12 +198,6 @@ void Tempo::getWorkloadByAccount(const QString &accountKey, QDate from, QDate to
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tempo::onRefreshTimer()
|
|
||||||
{
|
|
||||||
qCDebug(dcTempo()) << "Refresh authentication token";
|
|
||||||
getAccessTokenFromRefreshToken(m_refreshToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Tempo::setAuthenticated(bool state)
|
void Tempo::setAuthenticated(bool state)
|
||||||
{
|
{
|
||||||
if (state != m_authenticated) {
|
if (state != m_authenticated) {
|
||||||
|
|||||||
@ -102,31 +102,29 @@ public:
|
|||||||
QString authorDisplayName;
|
QString authorDisplayName;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit Tempo(NetworkAccessManager *networkmanager, const QByteArray &clientId, const QByteArray &clientSecret, QObject *parent = nullptr);
|
struct Team {
|
||||||
QByteArray accessToken();
|
QUrl self;
|
||||||
QByteArray refreshToken();
|
int id;
|
||||||
|
QString name;
|
||||||
|
QString summary;
|
||||||
|
Lead lead;
|
||||||
|
};
|
||||||
|
|
||||||
QUrl getLoginUrl(const QUrl &redirectUrl, const QString &jiraCloudInstanceName);
|
explicit Tempo(NetworkAccessManager *networkmanager, const QString &jiraCloudInstanceName, const QString &token, QObject *parent = nullptr);
|
||||||
|
~Tempo() override;
|
||||||
void getAccessTokenFromRefreshToken(const QByteArray &refreshToken);
|
QString token() const;
|
||||||
void getAccessTokenFromAuthorizationCode(const QByteArray &authorizationCode);
|
|
||||||
|
|
||||||
|
void getTeams();
|
||||||
void getAccounts();
|
void getAccounts();
|
||||||
void getWorkloadByAccount(const QString &accountKey, QDate from, QDate to);
|
void getWorkloadByAccount(const QString &accountKey, QDate from, QDate to);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QByteArray m_baseTokenUrl = "https://api.tempo.io/oauth/token/";
|
QByteArray m_baseTokenUrl = "https://api.tempo.io/oauth/token/";
|
||||||
QByteArray m_baseControlUrl = "https://api.tempo.io/core/3/";
|
QByteArray m_baseControlUrl = "https://api.tempo.io/core/3/";
|
||||||
QByteArray m_clientId;
|
QString m_token;
|
||||||
QByteArray m_clientSecret;
|
QString m_jiraCloudInstanceName;
|
||||||
|
|
||||||
QByteArray m_accessToken;
|
|
||||||
QByteArray m_refreshToken;
|
|
||||||
QByteArray m_redirectUri = "https://127.0.0.1:8888";
|
|
||||||
|
|
||||||
NetworkAccessManager *m_networkManager = nullptr;
|
NetworkAccessManager *m_networkManager = nullptr;
|
||||||
QTimer *m_tokenRefreshTimer = nullptr;
|
|
||||||
|
|
||||||
void setAuthenticated(bool state);
|
void setAuthenticated(bool state);
|
||||||
void setConnected(bool state);
|
void setConnected(bool state);
|
||||||
@ -135,16 +133,15 @@ private:
|
|||||||
bool m_connected = false;
|
bool m_connected = false;
|
||||||
|
|
||||||
bool checkStatusCode(QNetworkReply *reply, const QByteArray &rawData);
|
bool checkStatusCode(QNetworkReply *reply, const QByteArray &rawData);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onRefreshTimer();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void authenticationStatusChanged(bool state);
|
void authenticationStatusChanged(bool state);
|
||||||
void connectionChanged(bool connected);
|
void connectionChanged(bool connected);
|
||||||
void receivedRefreshToken(const QByteArray &refreshToken);
|
|
||||||
void receivedAccessToken(const QByteArray &accessToken);
|
|
||||||
void accountsReceived(const QList<Account> accounts);
|
|
||||||
|
|
||||||
|
void teamsReceived(const QList<Team> teams);
|
||||||
|
void accountsReceived(const QList<Account> accounts);
|
||||||
void accountWorklogsReceived(const QString &accountKey, QList<Worklog> worklogs);
|
void accountWorklogsReceived(const QString &accountKey, QList<Worklog> worklogs);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user