This repository has been archived on 2023-11-19. You can view files and clone it, but cannot push or open issues or pull requests.
goober-bb10/src/Pnut.cpp

635 lines
19 KiB
C++

/*
* Copyright (C) 2016 Morgan McMillian <gilag@monkeystew.com>
*
* This file is apart of the Goober application, a client for pnut.io
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Pnut.h"
#include "globals.h"
#include <QDebug>
#include <QDateTime>
#include <QRegExp>
#include <bb/data/JsonDataAccess>
const QString Pnut::PNUT_API_ROOT = QString("https://api.pnut.io/v0");
const QString Pnut::PNUT_AUTH_URL = QString("https://pnut.io/oauth/authenticate");
Pnut::Pnut()
{
req_id = 0;
before_id = 0;
since_id = 0;
authInProgress = false;
m_appSettings = new QSettings("Morgan McMillian", "Goober");
oauthRequest = new KQOAuthRequest;
oauthManager = new KQOAuthManager(this);
bool auth_req = connect(oauthManager, SIGNAL(authorizationReceived(QString,QString)),
this, SLOT(onAuthorizationReceived(QString,QString)));
Q_ASSERT(auth_req);
bool net_req = connect(oauthManager, SIGNAL(requestReady(QByteArray)),
this, SLOT(onRequestReady(QByteArray)));
Q_ASSERT(net_req);
bool conn_req = connect(oauthManager, SIGNAL(authorizedRequestReady(QByteArray,int)),
this, SLOT(onAuthorizedRequestReady(QByteArray,int)));
Q_ASSERT(conn_req);
bool brw_req = connect(oauthManager, SIGNAL(openBrowser(QUrl)),
this, SLOT(onOpenBrowser(QUrl)));
Q_ASSERT(brw_req);
qDebug() << "Pnut created, I am life.";
}
Pnut::~Pnut()
{
delete oauthRequest;
delete oauthManager;
qDebug() << "Pnut destroyed, I am death.";
}
int Pnut::sinceId() const
{
return since_id;
}
void Pnut::setSinceId(const int& id)
{
since_id = id;
}
int Pnut::beforeId() const
{
return before_id;
}
void Pnut::setBeforeId(const int& id)
{
before_id = id;
}
void Pnut::authorize()
{
if (authInProgress != true)
{
authInProgress = true;
QUrl url(PNUT_AUTH_URL);
KQOAuthParameters parameters;
parameters.insert("scope", "basic stream write_post follow update_profile presence");
oauthManager->getOauth2UserAuthorization(url, PNUT_CLIENT_ID, parameters);
}
}
void Pnut::getRequest(QUrl url, KQOAuthParameters parameters, int id)
{
oauthRequest->clearRequest();
oauthRequest->initRequest(KQOAuthRequest::AuthorizedRequest, url);
oauthRequest->setToken(m_appSettings->value("access_token").toString());
oauthRequest->setHttpMethod(KQOAuthRequest::GET);
oauthRequest->setRequestOAuthMethod(KQOAuthRequest::OAUTH2);
oauthRequest->setAdditionalParameters(parameters);
oauthManager->executeAuthorizedRequest(oauthRequest, id);
}
void Pnut::postRequest(QUrl url, KQOAuthParameters parameters, int id, QByteArray data)
{
oauthRequest->clearRequest();
oauthRequest->initRequest(KQOAuthRequest::AuthorizedRequest, url);
oauthRequest->setToken(m_appSettings->value("access_token").toString());
oauthRequest->setHttpMethod(KQOAuthRequest::POST);
oauthRequest->setRequestOAuthMethod(KQOAuthRequest::OAUTH2);
oauthRequest->setContentType("application/json");
oauthRequest->setAdditionalParameters(parameters);
oauthRequest->setRawData(data);
oauthManager->executeAuthorizedRequest(oauthRequest, id);
}
void Pnut::putRequest(QUrl url, KQOAuthParameters parameters, int id)
{
oauthRequest->clearRequest();
oauthRequest->initRequest(KQOAuthRequest::AuthorizedRequest, url);
oauthRequest->setToken(m_appSettings->value("access_token").toString());
oauthRequest->setHttpMethod(KQOAuthRequest::PUT);
oauthRequest->setRequestOAuthMethod(KQOAuthRequest::OAUTH2);
oauthRequest->setAdditionalParameters(parameters);
oauthManager->executeAuthorizedRequest(oauthRequest, id);
}
void Pnut::deleteRequest(QUrl url, KQOAuthParameters parameters, int id)
{
oauthRequest->clearRequest();
oauthRequest->initRequest(KQOAuthRequest::AuthorizedRequest, url);
oauthRequest->setToken(m_appSettings->value("access_token").toString());
oauthRequest->setHttpMethod(KQOAuthRequest::DELETE);
oauthRequest->setRequestOAuthMethod(KQOAuthRequest::OAUTH2);
oauthRequest->setAdditionalParameters(parameters);
oauthManager->executeAuthorizedRequest(oauthRequest, id);
}
void Pnut::onAuthorizationReceived(QString token, QString verifier)
{
qDebug() << "--check check--";
qDebug() << oauthManager->lastError();
qDebug() << "token: " << token;
qDebug() << "verif: " << verifier;
switch (oauthManager->lastError())
{
case KQOAuthManager::RequestValidationError:
case KQOAuthManager::NoError:
qDebug() << "- authorization received -";
m_appSettings->setValue("access_token", token);
getUserInfo();
emit authorizationReceived();
break;
default:
qDebug() << "- authorization error -";
qDebug() << oauthManager->lastError();
}
authInProgress = false;
}
void Pnut::onRequestReady(QByteArray data)
{
qDebug() << "- onRequestReady -";
switch (oauthManager->lastError())
{
case KQOAuthManager::RequestUnauthorized:
qDebug() << "- Unauthorized -";
m_appSettings->remove("access_token");
m_appSettings->remove("username");
emit authorizationRequired();
break;
case KQOAuthManager::NetworkError:
qDebug() << "- NetworkError -";
getUserInfo();
break;
default:
qDebug() << "- other? -";
qDebug() << oauthManager->lastError();
}
}
void Pnut::onAuthorizedRequestReady(QByteArray data, int id)
{
QString endpoint = req_map[id];
qDebug() << "- onAuthorizedRequestReady";
qDebug() << "- id: " << id;
qDebug() << "- endpoint: " << endpoint;
qDebug() << data;
QVariant variant;
bb::data::JsonDataAccess jda;
variant = jda.loadFromBuffer(data);
QVariantMap meta = variant.toMap()["meta"].toMap();
int code = meta["code"].toInt();
switch (code)
{
case Pnut::OK:
{
if (endpoint.startsWith("/posts/streams/") ||
endpoint == "/users/me/mentions" ||
endpoint == "/users/me/bookmarks")
{
Pnut::RequestType rtype = rtype_map[id];
QVariantList streamlist = variant.toMap()["data"].toList();
emit streamReceived(parseStream(streamlist), rtype);
req_map.remove(id);
rtype_map.remove(id);
}
else if (endpoint == ":me")
{
QVariantMap userinfo(variant.toMap()["data"].toMap());
m_appSettings->setValue("username", userinfo.value("username").toString());
}
else if (endpoint == ":thread")
{
QVariantList streamlist = variant.toMap()["data"].toList();
emit threadReceived(parseStream(streamlist));
req_map.remove(id);
}
else if (endpoint == ":userstream")
{
emit userStreamReceived(variant.toMap()["data"].toList());
req_map.remove(id);
}
else if (endpoint == ":followers" || endpoint == ":following")
{
emit userListReceived(variant.toMap()["data"].toList());
req_map.remove(id);
}
else if (endpoint == ":logout")
{
qDebug() << "Logout successful!";
req_map.remove(id);
m_appSettings->remove("access_token");
m_appSettings->remove("username");
emit authorizationRequired();
}
else if (endpoint == ":follow")
{
qDebug() << "Follow successful!";
req_map.remove(id);
emit followSuccess(variant.toMap()["data"].toMap());
}
else if (endpoint == ":unfollow")
{
qDebug() << "Unfollow successful!";
req_map.remove(id);
emit unfollowSuccess(variant.toMap()["data"].toMap());
}
else if (endpoint == ":block")
{
qDebug() << "Block successful!";
req_map.remove(id);
emit blockSuccess(variant.toMap()["data"].toMap());
}
else if (endpoint == ":unblock")
{
qDebug() << "Unblock successful!";
req_map.remove(id);
emit unblockSuccess(variant.toMap()["data"].toMap());
}
else if (endpoint == ":mute")
{
qDebug() << "Mute successful!";
req_map.remove(id);
emit muteSuccess(variant.toMap()["data"].toMap());
}
else if (endpoint == ":unmute")
{
qDebug() << "Unmute successful!";
req_map.remove(id);
emit unmuteSuccess(variant.toMap()["data"].toMap());
}
else if (endpoint.startsWith(":getpost:"))
{
qDebug() << "Got a post!";
req_map.remove(id);
emit postReceived(variant.toMap()["data"].toMap());
}
else if (endpoint.startsWith(":deletepost:"))
{
qDebug() << "Delete successful!";
req_map.remove(id);
QString gpid = endpoint.replace(":deletepost:","");
getPost(gpid);
}
else if (endpoint.startsWith(":bookmark"))
{
qDebug() << "Bookmark successful!";
req_map.remove(id);
getPost(variant.toMap()["data"].toMap()["id"].toString());
}
else if (endpoint.startsWith(":repost"))
{
qDebug() << "Repost successful!";
req_map.remove(id);
getPost(variant.toMap()["data"].toMap()["id"].toString());
}
else
{
qDebug() << "GOT SOMETHING NEW!";
qDebug() << endpoint;
}
break;
}
case Pnut::CREATED:
{
if (endpoint == "/posts")
{
qDebug() << "Create post success!";
req_map.remove(id);
}
else if (endpoint.startsWith(":repost"))
{
qDebug() << "Repost successful!";
req_map.remove(id);
getPost(variant.toMap()["data"].toMap()["id"].toString());
}
else
{
qDebug() << "Good but not sure what";
req_map.remove(id);
}
break;
}
default:
{
qDebug() << ":: Error - " << code;
qDebug() << meta;
}
}
}
void Pnut::getStream(QString endpoint, Pnut::RequestType rtype)
{
QUrl url(PNUT_API_ROOT + endpoint);
KQOAuthParameters parameters;
parameters.insert("count", "50");
parameters.insert("include_post_raw", "1");
switch (rtype)
{
case Pnut::STREAM_NEWER:
if (since_id > 0) parameters.insert("since_id", QString::number(since_id));
break;
case Pnut::STREAM_OLDER:
if (before_id > 0) parameters.insert("before_id", QString::number(before_id));
break;
}
req_map[++req_id] = endpoint;
rtype_map[req_id] = rtype;
getRequest(url, parameters, req_id);
}
void Pnut::sendPost(QString text, int pid=0)
{
QByteArray post;
QVariantMap map;
QVariantList raw;
if (postLength(text) > 256)
{
QVariantMap longpost;
QVariantMap rawobj;
longpost["title"] = "";
longpost["body"] = text;
longpost["tstamp"] = QDateTime::currentMSecsSinceEpoch();
rawobj["type"] = "nl.chimpnut.blog.post";
rawobj["value"] = longpost;
raw.append(rawobj);
text.truncate(100);
text = text + "... - https://longpo.st/p/{object_id} - #longpost";
}
map["text"] = text;
if (pid > 0)
{
map["reply_to"] = pid;
}
if (raw.length() > 0)
{
map["raw"] = raw;
}
QVariant data(map);
bb::data::JsonDataAccess jda;
jda.saveToBuffer(data, &post);
QUrl url(PNUT_API_ROOT + "/posts");
KQOAuthParameters parameters;
req_map[++req_id] = "/posts";
postRequest(url, parameters, req_id, post);
}
void Pnut::sendReply(QString text, int pid)
{
QByteArray post;
QVariantMap map;
map["text"] = text;
map["reply_to"] = pid;
QVariant data(map);
bb::data::JsonDataAccess jda;
jda.saveToBuffer(data, &post);
QUrl url(PNUT_API_ROOT + "/posts");
KQOAuthParameters parameters;
req_map[++req_id] = "/posts";
postRequest(url, parameters, req_id, post);
}
void Pnut::getUser(QString uid)
{
QUrl url(PNUT_API_ROOT + "/users/" + uid);
KQOAuthParameters parameters;
req_map[++req_id] = "/users/" + uid;
getRequest(url, parameters, req_id);
}
void Pnut::getUserInfo()
{
QUrl url(PNUT_API_ROOT + "/users/me");
KQOAuthParameters parameters;
req_map[++req_id] = ":me";
getRequest(url, parameters, req_id);
}
void Pnut::getThread(QString pid)
{
QUrl url(PNUT_API_ROOT + "/posts/" + pid + "/thread");
KQOAuthParameters parameters;
parameters.insert("include_post_raw", "1");
req_map[++req_id] = ":thread";
getRequest(url, parameters, req_id);
}
void Pnut::setBookmark(QString pid)
{
QUrl url(PNUT_API_ROOT + "/posts/" + pid + "/bookmark");
KQOAuthParameters parameters;
parameters.insert("include_post_raw", "1");
req_map[++req_id] = ":bookmark";
putRequest(url, parameters, req_id);
}
void Pnut::deleteBookmark(QString pid)
{
QUrl url(PNUT_API_ROOT + "/posts/" + pid + "/bookmark");
KQOAuthParameters parameters;
parameters.insert("include_post_raw", "1");
req_map[++req_id] = ":bookmark";
deleteRequest(url, parameters, req_id);
}
void Pnut::repost(QString pid) {
QUrl url(PNUT_API_ROOT + "/posts/" + pid + "/repost");
KQOAuthParameters parameters;
parameters.insert("include_post_raw", "1");
req_map[++req_id] = ":repost";
putRequest(url, parameters, req_id);
}
void Pnut::deleteRepost(QString pid)
{
QUrl url(PNUT_API_ROOT + "/posts/" + pid + "/repost");
KQOAuthParameters parameters;
parameters.insert("include_post_raw", "1");
req_map[++req_id] = ":repost";
deleteRequest(url, parameters, req_id);
}
void Pnut::logout()
{
QUrl url(PNUT_API_ROOT + "/token");
KQOAuthParameters parameters;
req_map[++req_id] = ":logout";
deleteRequest(url, parameters, req_id);
}
void Pnut::followUser(QString uid)
{
QUrl url(PNUT_API_ROOT + "/users/" + uid + "/follow");
KQOAuthParameters parameters;
req_map[++req_id] = ":follow";
putRequest(url, parameters, req_id);
}
void Pnut::unfollowUser(QString uid)
{
QUrl url(PNUT_API_ROOT + "/users/" + uid + "/follow");
KQOAuthParameters parameters;
req_map[++req_id] = ":unfollow";
deleteRequest(url, parameters, req_id);
}
void Pnut::blockUser(QString uid)
{
QUrl url(PNUT_API_ROOT + "/users/" + uid + "/block");
KQOAuthParameters parameters;
req_map[++req_id] = ":block";
putRequest(url, parameters, req_id);
}
void Pnut::unblockUser(QString uid)
{
QUrl url(PNUT_API_ROOT + "/users/" + uid + "/block");
KQOAuthParameters parameters;
req_map[++req_id] = ":unblock";
deleteRequest(url, parameters, req_id);
}
void Pnut::muteUser(QString uid)
{
QUrl url(PNUT_API_ROOT + "/users/" + uid + "/mute");
KQOAuthParameters parameters;
req_map[++req_id] = ":mute";
putRequest(url, parameters, req_id);
}
void Pnut::unmuteUser(QString uid)
{
QUrl url(PNUT_API_ROOT + "/users/" + uid + "/mute");
KQOAuthParameters parameters;
req_map[++req_id] = ":unmute";
deleteRequest(url, parameters, req_id);
}
void Pnut::deletePost(QString pid)
{
QUrl url(PNUT_API_ROOT + "/posts/" + pid);
KQOAuthParameters parameters;
req_map[++req_id] = ":deletepost:" + pid;
deleteRequest(url, parameters, req_id);
}
void Pnut::getPost(QString pid)
{
QUrl url(PNUT_API_ROOT + "/posts/" + pid);
KQOAuthParameters parameters;
parameters.insert("include_post_raw", "1");
req_map[++req_id] = ":getpost:" + pid;
getRequest(url, parameters, req_id);
}
void Pnut::getUserStream(QString uid)
{
QUrl url(PNUT_API_ROOT + "/users/" + uid + "/posts");
KQOAuthParameters parameters;
parameters.insert("count", "150");
parameters.insert("include_post_raw", "1");
req_map[++req_id] = ":userstream";
getRequest(url, parameters, req_id);
}
void Pnut::getFollowers(QString uid)
{
QUrl url(PNUT_API_ROOT + "/users/" + uid + "/followers");
KQOAuthParameters parameters;
req_map[++req_id] = ":followers";
getRequest(url, parameters, req_id);
}
void Pnut::getFollowing(QString uid)
{
QUrl url(PNUT_API_ROOT + "/users/" + uid + "/following");
KQOAuthParameters parameters;
req_map[++req_id] = ":following";
getRequest(url, parameters, req_id);
}
int Pnut::postLength(QString text)
{
QRegExp mdlink("\\[([^\\]]+)\\][^\\)]+\\)");
text.replace(mdlink, "\\1");
return text.length();
}
void Pnut::onOpenBrowser(QUrl url)
{
qDebug() << "_onOpenBrowser_";
qDebug() << url;
emit openBrowser(url);
}
QVariantList Pnut::parseStream(QVariantList stream)
{
QVariantList pstream;
foreach (QVariant vitem, stream) {
QVariantMap item = vitem.toMap();
if (item.find("repost_of") != item.end())
{
QString username = item["user"].toMap()["username"].toString();
item = item["repost_of"].toMap();
item.insert("reposted_by", username);
}
if (item.find("raw") != item.end())
{
QVariantList rawlist = item["raw"].toList();
foreach (QVariant ritem, rawlist) {
QVariantMap raw = ritem.toMap();
if (raw["type"] == "io.pnut.core.oembed")
{
QVariantMap value = raw["value"].toMap();
if (value["type"] == "photo")
{
item.insert("photo_url", value["url"].toString());
if (value.find("thumbnail_url") != value.end())
{
item.insert("thumbnail_url", value["thumbnail_url"].toString());
}
}
}
if (raw["type"] == "nl.chimpnut.blog.post") {
QVariantMap value = raw["value"].toMap();
item.insert("longpost_body", value["body"]);
}
}
}
pstream.append(item);
}
return pstream;
}