diff --git a/microblogs/mastodon/mastodoncomposerwidget.cpp b/microblogs/mastodon/mastodoncomposerwidget.cpp index 32e525c5..fe6f2573 100644 --- a/microblogs/mastodon/mastodoncomposerwidget.cpp +++ b/microblogs/mastodon/mastodoncomposerwidget.cpp @@ -1,169 +1,169 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2017 Andrea Scarpino 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 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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 "mastodoncomposerwidget.h" #include #include #include #include #include #include #include #include "account.h" #include "choqoktextedit.h" #include "shortenmanager.h" #include "mastodondebug.h" #include "mastodonmicroblog.h" #include "mastodonpost.h" class MastodonComposerWidget::Private { public: QString mediumToAttach; QPushButton *btnAttach; QPointer mediumName; QPointer btnCancel; QGridLayout *editorLayout; }; MastodonComposerWidget::MastodonComposerWidget(Choqok::Account *account, QWidget *parent) : ComposerWidget(account, parent) , d(new Private) { d->editorLayout = qobject_cast(editorContainer()->layout()); d->btnAttach = new QPushButton(editorContainer()); d->btnAttach->setIcon(QIcon::fromTheme(QLatin1String("mail-attachment"))); d->btnAttach->setToolTip(i18n("Attach a file")); d->btnAttach->setMaximumWidth(d->btnAttach->height()); connect(d->btnAttach, &QPushButton::clicked, this, &MastodonComposerWidget::attachMedia); QVBoxLayout *vLayout = new QVBoxLayout; vLayout->addWidget(d->btnAttach); vLayout->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Preferred, QSizePolicy::MinimumExpanding)); d->editorLayout->addItem(vLayout, 0, 1); } MastodonComposerWidget::~MastodonComposerWidget() { delete d; } void MastodonComposerWidget::submitPost(const QString &text) { qCDebug(CHOQOK); editorContainer()->setEnabled(false); QString txt = text; if (currentAccount()->postCharLimit() && txt.size() > (int) currentAccount()->postCharLimit()) { txt = Choqok::ShortenManager::self()->parseText(txt); } setPostToSubmit(nullptr); setPostToSubmit(new Choqok::Post); postToSubmit()->content = txt; if (!replyToId.isEmpty()) { postToSubmit()->replyToPostId = replyToId; } connect(currentAccount()->microblog(), &Choqok::MicroBlog::postCreated, this, &MastodonComposerWidget::slotPostSubmited); connect(currentAccount()->microblog(), &Choqok::MicroBlog::errorPost, this, &MastodonComposerWidget::slotErrorPost); btnAbort = new QPushButton(QIcon::fromTheme(QLatin1String("dialog-cancel")), i18n("Abort"), this); layout()->addWidget(btnAbort); connect(btnAbort, &QPushButton::clicked, this, &MastodonComposerWidget::abort); MastodonMicroBlog *mBlog = qobject_cast(currentAccount()->microblog()); if (d->mediumToAttach.isEmpty()) { if (replyToId.isEmpty()) { currentAccount()->microblog()->createPost(currentAccount(), postToSubmit()); } else { // WTF? It seems we cannot cast postToSubmit to MastodonPost and then I'm copying its attributes MastodonPost *pumpPost = new MastodonPost(); pumpPost->content = postToSubmit()->content; pumpPost->replyToPostId = postToSubmit()->replyToPostId; setPostToSubmit(pumpPost); mBlog->createReply(currentAccount(), pumpPost); } } else { // TODO // mBlog->createPostWithMedia(currentAccount(), postToSubmit(), d->mediumToAttach); } } void MastodonComposerWidget::slotPostSubmited(Choqok::Account *theAccount, Choqok::Post *post) { qCDebug(CHOQOK); if (currentAccount() == theAccount && post == postToSubmit()) { qCDebug(CHOQOK) << "Accepted"; disconnect(currentAccount()->microblog(), &Choqok::MicroBlog::postCreated, this, &MastodonComposerWidget::slotPostSubmited); disconnect(currentAccount()->microblog(), &Choqok::MicroBlog::errorPost, this, &MastodonComposerWidget::slotErrorPost); if (btnAbort) { btnAbort->deleteLater(); } editor()->clear(); editorCleared(); editorContainer()->setEnabled(true); setPostToSubmit(nullptr); cancelAttach(); currentAccount()->microblog()->updateTimelines(currentAccount()); } } void MastodonComposerWidget::attachMedia() { qCDebug(CHOQOK); d->mediumToAttach = QFileDialog::getOpenFileName(this, i18n("Select Media to Upload"), QString(), QStringLiteral("Images")); if (d->mediumToAttach.isEmpty()) { qCDebug(CHOQOK) << "No file selected"; return; } const QString fileName = QUrl(d->mediumToAttach).fileName(); if (!d->mediumName) { d->mediumName = new QLabel(editorContainer()); d->btnCancel = new QPushButton(editorContainer()); d->btnCancel->setIcon(QIcon::fromTheme(QLatin1String("list-remove"))); d->btnCancel->setToolTip(i18n("Discard Attachment")); d->btnCancel->setMaximumWidth(d->btnCancel->height()); connect(d->btnCancel, &QPushButton::clicked, this, &MastodonComposerWidget::cancelAttach); d->editorLayout->addWidget(d->mediumName, 1, 0); d->editorLayout->addWidget(d->btnCancel, 1, 1); } d->mediumName->setText(i18n("Attaching %1", fileName)); editor()->setFocus(); } void MastodonComposerWidget::cancelAttach() { qCDebug(CHOQOK); delete d->mediumName; - d->mediumName = 0; + d->mediumName = nullptr; delete d->btnCancel; - d->btnCancel = 0; + d->btnCancel = nullptr; d->mediumToAttach.clear(); } diff --git a/microblogs/mastodon/mastodondmessagedialog.h b/microblogs/mastodon/mastodondmessagedialog.h index 0b139643..cb88420d 100644 --- a/microblogs/mastodon/mastodondmessagedialog.h +++ b/microblogs/mastodon/mastodondmessagedialog.h @@ -1,72 +1,72 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2017 Andrea Scarpino 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 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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/ */ #ifndef MASTODONDMESSAGEDIALOG_H #define MASTODONDMESSAGEDIALOG_H #include #include "microblog.h" namespace Choqok { class Account; class Post; namespace UI { class TextEdit; } } class MastodonAccount; class MastodonDMessageDialog : public QDialog { Q_OBJECT public: - explicit MastodonDMessageDialog(MastodonAccount *theAccount, QWidget *parent = 0, Qt::WindowFlags flags = 0); + explicit MastodonDMessageDialog(MastodonAccount *theAccount, QWidget *parent = nullptr, Qt::WindowFlags flags = nullptr); ~MastodonDMessageDialog(); void setTo(const QString &username); protected Q_SLOTS: virtual void accept() override; void followersUsernameListed(MastodonAccount *, QStringList); void submitPost(QString); void reloadFriendslist(); void errorPost(Choqok::Account *, Choqok::Post *, Choqok::MicroBlog::ErrorType, QString, Choqok::MicroBlog::ErrorLevel); protected: void setupUi(QWidget *mainWidget); void setFriends(const QStringList friends); Choqok::UI::TextEdit *editor(); MastodonAccount *account(); private: class Private; Private *const d; }; #endif // MASTODONDMESSAGEDIALOG_H diff --git a/microblogs/mastodon/mastodonmicroblog.cpp b/microblogs/mastodon/mastodonmicroblog.cpp index a850305b..cb3bac5a 100644 --- a/microblogs/mastodon/mastodonmicroblog.cpp +++ b/microblogs/mastodon/mastodonmicroblog.cpp @@ -1,990 +1,990 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2017 Andrea Scarpino 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 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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 "mastodonmicroblog.h" #include #include #include #include #include #include #include #include #include #include "accountmanager.h" #include "application.h" #include "choqokappearancesettings.h" #include "choqokbehaviorsettings.h" #include "notifymanager.h" #include "postwidget.h" #include "mastodonaccount.h" #include "mastodoncomposerwidget.h" #include "mastodondebug.h" #include "mastodondmessagedialog.h" #include "mastodoneditaccountwidget.h" #include "mastodonpost.h" #include "mastodonpostwidget.h" class MastodonMicroBlog::Private { public: Private(): countOfTimelinesToSave(0) {} int countOfTimelinesToSave; }; K_PLUGIN_FACTORY_WITH_JSON(MastodonMicroBlogFactory, "choqok_mastodon.json", registerPlugin < MastodonMicroBlog > ();) const QString MastodonMicroBlog::homeTimeline(QLatin1String("/api/v1/timelines/home")); const QString MastodonMicroBlog::publicTimeline(QLatin1String("/api/v1/timelines/public")); const QString MastodonMicroBlog::favouritesTimeline(QLatin1String("/api/v1/favourites")); MastodonMicroBlog::MastodonMicroBlog(QObject *parent, const QVariantList &args): MicroBlog(QStringLiteral("Mastodon") , parent), d(new Private) { Q_UNUSED(args) setServiceName(QLatin1String("Mastodon")); setServiceHomepageUrl(QLatin1String("https://mastodon.social")); QStringList timelineNames; timelineNames << QLatin1String("Home") << QLatin1String("Local") << QLatin1String("Federated") << QLatin1String("Favourites"); setTimelineNames(timelineNames); setTimelinesInfo(); } MastodonMicroBlog::~MastodonMicroBlog() { qDeleteAll(m_timelinesInfos); delete d; } void MastodonMicroBlog::aboutToUnload() { for (Choqok::Account *acc: Choqok::AccountManager::self()->accounts()) { if (acc->microblog() == this) { d->countOfTimelinesToSave += acc->timelineNames().count(); } } Q_EMIT saveTimelines(); } ChoqokEditAccountWidget *MastodonMicroBlog::createEditAccountWidget(Choqok::Account *account, QWidget *parent) { MastodonAccount *acc = qobject_cast(account); if (acc || !account) { return new MastodonEditAccountWidget(this, acc, parent); } else { qCDebug(CHOQOK) << "Account passed here was not a valid MastodonAccount!"; - return 0; + return nullptr; } } Choqok::UI::ComposerWidget *MastodonMicroBlog::createComposerWidget(Choqok::Account *account, QWidget *parent) { return new MastodonComposerWidget(account, parent); } void MastodonMicroBlog::createPost(Choqok::Account *theAccount, Choqok::Post *post) { if (!post || post->content.isEmpty()) { qCDebug(CHOQOK) << "ERROR: Status text is empty!"; Q_EMIT errorPost(theAccount, post, Choqok::MicroBlog::OtherError, i18n("Creating the new post failed. Text is empty."), MicroBlog::Critical); return; } MastodonAccount *acc = qobject_cast(theAccount); if (acc) { QVariantMap object; object.insert(QLatin1String("status"), post->content); const QByteArray data = QJsonDocument::fromVariant(object).toJson(); QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QLatin1String("/api/v1/statuses")); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo); job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: application/json")); job->addMetaData(QLatin1String("customHTTPHeader"), authorizationMetaData(acc)); if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; return; } m_accountJobs[job] = acc; m_createPostJobs[job] = post; connect(job, &KIO::StoredTransferJob::result, this, &MastodonMicroBlog::slotCreatePost); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a MastodonAccount!"; } } Choqok::Account *MastodonMicroBlog::createNewAccount(const QString &alias) { MastodonAccount *acc = qobject_cast( Choqok::AccountManager::self()->findAccount(alias)); if (!acc) { return new MastodonAccount(this, alias); } else { qCDebug(CHOQOK) << "Cannot create a new MastodonAccount!"; - return 0; + return nullptr; } } QString MastodonMicroBlog::lastTimelineId(Choqok::Account *theAccount, const QString &timeline) const { qCDebug(CHOQOK) << "Latest ID for timeline " << timeline << m_timelinesLatestIds[theAccount][timeline]; return m_timelinesLatestIds[theAccount][timeline]; } QList< Choqok::Post * > MastodonMicroBlog::readTimeline(const QByteArray &buffer) { QList posts; const QJsonDocument json = QJsonDocument::fromJson(buffer); if (!json.isNull()) { const QVariantList list = json.array().toVariantList(); for (const QVariant &element: list) { posts.prepend(readPost(element.toMap(), new MastodonPost)); } } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } return posts; } Choqok::Post *MastodonMicroBlog::readPost(const QVariantMap &var, Choqok::Post *post) { MastodonPost *p = dynamic_cast< MastodonPost * >(post); if (p) { QVariantMap reblog = var[QLatin1String("reblog")].toMap(); QVariantMap status; if (reblog.isEmpty()) { status = var; } else { status = reblog; } QTextDocument content; content.setHtml(status[QLatin1String("spoiler_text")].toString() + QLatin1String("
") + status[QLatin1String("content")].toString()); p->content += content.toPlainText().trimmed(); p->creationDateTime = QDateTime::fromString(var[QLatin1String("created_at")].toString(), Qt::ISODate); p->creationDateTime.setTimeSpec(Qt::UTC); p->link = status[QLatin1String("url")].toUrl(); p->isFavorited = var[QLatin1String("favourited")].toBool(); if (p->isFavorited) { p->isRead = true; } p->postId = var[QLatin1String("id")].toString(); p->conversationId = var[QLatin1String("id")].toString(); QVariantMap application = var[QLatin1String("application")].toMap(); if (!application.isEmpty()) { const QString client = application[QLatin1String("name")].toString(); if (application[QLatin1String("website")].toString().isEmpty()) { p->source = client; } else { p->source = QStringLiteral("%2").arg(application[QLatin1String("website")].toString()).arg(client); } } if (var[QLatin1String("visibility")].toString().compare(QLatin1String("direct")) == 0) { p->isPrivate = true; } QVariantMap account = status[QLatin1Literal("account")].toMap(); p->author.userId = account[QLatin1String("id")].toString(); p->author.userName = account[QLatin1String("acct")].toString(); p->author.realName = account[QLatin1String("display_name")].toString(); p->author.homePageUrl = account[QLatin1String("url")].toUrl(); QTextDocument description; description.setHtml(account[QLatin1String("note")].toString()); p->author.description = description.toPlainText().trimmed(); p->author.profileImageUrl = account[QLatin1String("avatar")].toUrl(); p->replyToPostId = var[QLatin1String("in_reply_to_id")].toString(); p->replyToUser.userId = var[QLatin1String("in_reply_to_account_id")].toString(); if (!reblog.isEmpty()) { p->repeatedDateTime = QDateTime::fromString(var[QLatin1String("created_at")].toString(), Qt::ISODate); p->repeatedDateTime.setTimeSpec(Qt::UTC); p->repeatedPostId = var[QLatin1String("id")].toString(); const QVariantMap repeatedFrom = var[QLatin1Literal("account")].toMap(); p->repeatedFromUser.userId = repeatedFrom[QLatin1String("id")].toString(); p->repeatedFromUser.userName = repeatedFrom[QLatin1String("acct")].toString(); p->repeatedFromUser.homePageUrl = repeatedFrom[QLatin1String("url")].toUrl(); } return p; } else { qCDebug(CHOQOK) << "post is not a MastodonPost!"; return post; } } void MastodonMicroBlog::createReply(Choqok::Account *theAccount, MastodonPost *post) { MastodonAccount *acc = qobject_cast(theAccount); if (acc) { QVariantMap object; object.insert(QLatin1String("status"), post->content); if (!post->replyToPostId.isEmpty()) { object.insert(QLatin1String("in_reply_to_id"), post->replyToPostId); } const QByteArray data = QJsonDocument::fromVariant(object).toJson(); QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QLatin1String("/api/v1/statuses")); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo); job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: application/json")); job->addMetaData(QLatin1String("customHTTPHeader"), authorizationMetaData(acc)); if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; return; } m_accountJobs[job] = acc; m_createPostJobs[job] = post; connect(job, &KIO::StoredTransferJob::result, this, &MastodonMicroBlog::slotCreatePost); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a MastodonAccount!"; } } void MastodonMicroBlog::toggleReblog(Choqok::Account *theAccount, Choqok::Post *post) { MastodonAccount *acc = qobject_cast(theAccount); if (acc) { QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); if (acc->username().compare(post->repeatedFromUser.userName) == 0) { url.setPath(url.path() + QStringLiteral("/api/v1/statuses/%1/unreblog").arg(post->postId)); } else { url.setPath(url.path() + QStringLiteral("/api/v1/statuses/%1/reblog").arg(post->postId)); } KIO::StoredTransferJob *job = KIO::storedHttpPost(QByteArray(), url, KIO::HideProgressInfo); job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: application/json")); job->addMetaData(QLatin1String("customHTTPHeader"), authorizationMetaData(acc)); if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; return; } m_accountJobs[job] = acc; m_shareJobs[job] = post; connect(job, &KIO::StoredTransferJob::result, this, &MastodonMicroBlog::slotReblog); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a MastodonAccount!"; } } void MastodonMicroBlog::slotReblog(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Post *post = m_shareJobs.take(job); Choqok::Account *theAccount = m_accountJobs.take(job); if (!post || !theAccount) { qCDebug(CHOQOK) << "Account or Post is NULL pointer"; return; } int ret = 1; if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); } else { Choqok::UI::Global::mainWindow()->showStatusMessage(i18n("The post has been shared.")); KIO::StoredTransferJob *j = qobject_cast(job); const QJsonDocument json = QJsonDocument::fromJson(j->data()); if (!json.isNull()) { ret = 0; } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } if (ret) { Q_EMIT error(theAccount, Choqok::MicroBlog::CommunicationError, i18n("Cannot share the post. %1", job->errorString())); } } void MastodonMicroBlog::toggleFavorite(Choqok::Account *theAccount, Choqok::Post *post) { MastodonAccount *acc = qobject_cast(theAccount); if (acc) { QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); if (post->isFavorited) { url.setPath(url.path() + QStringLiteral("/api/v1/statuses/%1/unfavourite").arg(post->postId)); } else { url.setPath(url.path() + QStringLiteral("/api/v1/statuses/%1/favourite").arg(post->postId)); } KIO::StoredTransferJob *job = KIO::storedHttpPost(QByteArray(), url, KIO::HideProgressInfo); job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: application/json")); job->addMetaData(QLatin1String("customHTTPHeader"), authorizationMetaData(acc)); if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; return; } m_accountJobs[job] = acc; m_favoriteJobs[job] = post; connect(job, &KIO::StoredTransferJob::result, this, &MastodonMicroBlog::slotFavorite); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a MastodonAccount!"; } } void MastodonMicroBlog::slotFavorite(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Post *post = m_favoriteJobs.take(job); Choqok::Account *theAccount = m_accountJobs.take(job); if (!post || !theAccount) { qCDebug(CHOQOK) << "Account or Post is NULL pointer"; return; } if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(theAccount, Choqok::MicroBlog::CommunicationError, i18n("Cannot set/unset the post as favorite. %1", job->errorString())); } else { post->isFavorited = !post->isFavorited; Q_EMIT favorite(theAccount, post); } } void MastodonMicroBlog::setLastTimelineId(Choqok::Account *theAccount, const QString &timeline, const QString &id) { m_timelinesLatestIds[theAccount][timeline] = id; } void MastodonMicroBlog::setTimelinesInfo() { Choqok::TimelineInfo *t = new Choqok::TimelineInfo; t->name = i18nc("Timeline Name", "Home"); t->description = i18nc("Timeline description", "You and people you follow"); t->icon = QLatin1String("user-home"); m_timelinesInfos[QLatin1String("Home")] = t; m_timelinesPaths[QLatin1String("Home")] = homeTimeline; t = new Choqok::TimelineInfo; t->name = i18nc("Timeline Name", "Local"); t->description = i18nc("Timeline description", "Local timeline"); t->icon = QLatin1String("folder-public"); m_timelinesInfos[QLatin1String("Local")] = t; m_timelinesPaths[QLatin1String("Local")] = publicTimeline; t = new Choqok::TimelineInfo; t->name = i18nc("Timeline Name", "Federated"); t->description = i18nc("Timeline description", "Federated timeline"); t->icon = QLatin1String("folder-remote"); m_timelinesInfos[QLatin1String("Federated")] = t; m_timelinesPaths[QLatin1String("Federated")] = publicTimeline; t = new Choqok::TimelineInfo; t->name = i18nc("Timeline Name", "Favourites"); t->description = i18nc("Timeline description", "Favourites"); t->icon = QLatin1String("favorites"); m_timelinesInfos[QLatin1String("Favourites")] = t; m_timelinesPaths[QLatin1String("Favourites")] = favouritesTimeline; } void MastodonMicroBlog::removePost(Choqok::Account *theAccount, Choqok::Post *post) { MastodonAccount *acc = qobject_cast(theAccount); if (acc) { QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QStringLiteral("/api/v1/statuses/%1").arg(post->postId)); KIO::TransferJob *job = KIO::http_delete(url, KIO::HideProgressInfo); job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: application/json")); job->addMetaData(QLatin1String("customHTTPHeader"), authorizationMetaData(acc)); if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; return; } m_accountJobs[job] = acc; m_removePostJobs[job] = post; connect(job, &KIO::TransferJob::result, this, &MastodonMicroBlog::slotRemovePost); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a MastodonAccount!"; } } QList MastodonMicroBlog::loadTimeline(Choqok::Account *account, const QString &timelineName) { QList< Choqok::Post * > list; const QString fileName = Choqok::AccountManager::generatePostBackupFileName(account->alias(), timelineName); const KConfig postsBackup(fileName, KConfig::NoGlobals, QStandardPaths::DataLocation); const QStringList tmpList = postsBackup.groupList(); // don't load old archives if (tmpList.isEmpty() || !(QDateTime::fromString(tmpList.first()).isValid())) { return list; } QList groupList; for (const QString &str: tmpList) { groupList.append(QDateTime::fromString(str)); } std::sort(groupList.begin(), groupList.end()); MastodonPost *st; for (const QDateTime &datetime: groupList) { st = new MastodonPost; KConfigGroup grp(&postsBackup, datetime.toString()); st->creationDateTime = grp.readEntry("creationDateTime", QDateTime::currentDateTime()); st->postId = grp.readEntry("postId", QString()); st->link = grp.readEntry("link", QUrl()); st->content = grp.readEntry("content", QString()); st->source = grp.readEntry("source", QString()); st->isFavorited = grp.readEntry("favorited", false); st->author.userId = grp.readEntry("authorId", QString()); st->author.userName = grp.readEntry("authorUserName", QString()); st->author.realName = grp.readEntry("authorRealName", QString()); st->author.description = grp.readEntry("authorDescription" , QString()); st->author.profileImageUrl = grp.readEntry("authorProfileImageUrl", QUrl()); st->author.homePageUrl = grp.readEntry("authorHomePageUrl", QUrl()); st->isRead = grp.readEntry("isRead", true); st->conversationId = grp.readEntry("conversationId", QString()); st->replyToPostId = grp.readEntry("replyToPostId", QString()); st->replyToUser.userId = grp.readEntry("replyToUserId", QString()); st->repeatedFromUser.userId = grp.readEntry("repeatedFromUserId", QString()); st->repeatedFromUser.userName = grp.readEntry("repeatedFromUserName", QString()); st->repeatedFromUser.homePageUrl = grp.readEntry("repeatedFromUserHomePage", QUrl()); st->repeatedPostId = grp.readEntry("repeatedPostId", QString()); st->repeatedDateTime = grp.readEntry("repeatedDateTime", QDateTime()); list.append(st); } if (!list.isEmpty()) { setLastTimelineId(account, timelineName, list.last()->conversationId); } return list; } QUrl MastodonMicroBlog::profileUrl(Choqok::Account *account, const QString &username) const { if (username.contains(QLatin1Char('@'))) { return QUrl::fromUserInput(QStringLiteral("https://%1/@%2").arg(hostFromAcct(username)).arg(userNameFromAcct(username))); } else { MastodonAccount *acc = qobject_cast(account); QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(QLatin1String("/@") + username); return url; } } QString MastodonMicroBlog::generateRepeatedByUserTooltip(const QString &username) const { if (Choqok::AppearanceSettings::showRetweetsInChoqokWay()) { return i18n("Boost of %1", username); } else { return i18n("Boosted by %1", username); } } void MastodonMicroBlog::showDirectMessageDialog(MastodonAccount *theAccount, const QString &toUsername) { qCDebug(CHOQOK); if (!theAccount) { QAction *act = qobject_cast(sender()); theAccount = qobject_cast( Choqok::AccountManager::self()->findAccount(act->data().toString())); } MastodonDMessageDialog *dmsg = new MastodonDMessageDialog(theAccount, Choqok::UI::Global::mainWindow()); if (!toUsername.isEmpty()) { dmsg->setTo(toUsername); } dmsg->show(); } QString MastodonMicroBlog::hostFromAcct(const QString &acct) { if (acct.contains(QLatin1Char('@'))) { return acct.split(QLatin1Char('@'))[1]; } else { return acct; } } QString MastodonMicroBlog::userNameFromAcct(const QString &acct) { if (acct.contains(QLatin1Char('@'))) { return acct.split(QLatin1Char('@'))[0]; } else { return acct; } } void MastodonMicroBlog::saveTimeline(Choqok::Account *account, const QString &timelineName, const QList< Choqok::UI::PostWidget * > &timeline) { const QString fileName = Choqok::AccountManager::generatePostBackupFileName(account->alias(), timelineName); KConfig postsBackup(fileName, KConfig::NoGlobals, QStandardPaths::DataLocation); ///Clear previous data: for (const QString &group: postsBackup.groupList()) { postsBackup.deleteGroup(group); } for (Choqok::UI::PostWidget *wd: timeline) { MastodonPost *post = dynamic_cast(wd->currentPost()); KConfigGroup grp(&postsBackup, post->creationDateTime.toString()); grp.writeEntry("creationDateTime", post->creationDateTime); grp.writeEntry("postId", post->postId); grp.writeEntry("link", post->link); grp.writeEntry("content", post->content); grp.writeEntry("source", post->source); grp.writeEntry("favorited", post->isFavorited); grp.writeEntry("authorId", post->author.userId); grp.writeEntry("authorRealName", post->author.realName); grp.writeEntry("authorUserName", post->author.userName); grp.writeEntry("authorDescription", post->author.description); grp.writeEntry("authorProfileImageUrl", post->author.profileImageUrl); grp.writeEntry("authorHomePageUrl", post->author.homePageUrl); grp.writeEntry("isRead", post->isRead); grp.writeEntry("conversationId", post->conversationId); grp.writeEntry("replyToPostId", post->replyToPostId); grp.writeEntry("replyToUserId", post->replyToUser.userId); grp.writeEntry("repeatedFromUserId", post->repeatedFromUser.userId); grp.writeEntry("repeatedFromUserName", post->repeatedFromUser.userName); grp.writeEntry("repeatedFromUserHomePage", post->repeatedFromUser.homePageUrl); grp.writeEntry("repeatedPostId", post->repeatedPostId); grp.writeEntry("repeatedDateTime", post->repeatedDateTime); } postsBackup.sync(); if (Choqok::Application::isShuttingDown()) { --d->countOfTimelinesToSave; if (d->countOfTimelinesToSave < 1) { Q_EMIT readyForUnload(); } } } Choqok::TimelineInfo *MastodonMicroBlog::timelineInfo(const QString &timelineName) { return m_timelinesInfos.value(timelineName); } void MastodonMicroBlog::updateTimelines(Choqok::Account *theAccount) { MastodonAccount *acc = qobject_cast(theAccount); if (acc) { for (const QString &timeline: acc->timelineNames()) { QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QLatin1Char('/') + m_timelinesPaths[timeline]); QUrlQuery query; if (timeline.compare(QLatin1String("Local")) == 0) { query.addQueryItem(QLatin1String("local"), QLatin1String("true")); } url.setQuery(query); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; continue; } job->addMetaData(QLatin1String("customHTTPHeader"), authorizationMetaData(acc)); m_timelinesRequests[job] = timeline; m_accountJobs[job] = acc; connect(job, &KIO::StoredTransferJob::result, this, &MastodonMicroBlog::slotUpdateTimeline); job->start(); } } else { qCDebug(CHOQOK) << "theAccount is not a MastodonAccount!"; } } QString MastodonMicroBlog::authorizationMetaData(MastodonAccount *account) const { return QStringLiteral("Authorization: Bearer ") + account->oAuth()->token(); } Choqok::UI::PostWidget *MastodonMicroBlog::createPostWidget(Choqok::Account *account, Choqok::Post *post, QWidget *parent) { return new MastodonPostWidget(account, post, parent); } void MastodonMicroBlog::fetchPost(Choqok::Account *theAccount, Choqok::Post *post) { MastodonAccount *acc = qobject_cast(theAccount); if (acc) { if (!post->link.toDisplayString().startsWith(acc->host())) { qCDebug(CHOQOK) << "You can only fetch posts from your host!"; return; } QUrl url(post->link); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; return; } job->addMetaData(QLatin1String("customHTTPHeader"), authorizationMetaData(acc)); m_accountJobs[job] = acc; connect(job, &KIO::StoredTransferJob::result, this, &MastodonMicroBlog::slotFetchPost); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a MastodonAccount!"; } } void MastodonMicroBlog::slotCreatePost(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Post *post = m_createPostJobs.take(job); Choqok::Account *theAccount = m_accountJobs.take(job); if (!post || !theAccount) { qCDebug(CHOQOK) << "Account or Post is NULL pointer"; return; } int ret = 1; if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); } else { KIO::StoredTransferJob *j = qobject_cast(job); const QJsonDocument json = QJsonDocument::fromJson(j->data()); if (!json.isNull()) { const QVariantMap reply = json.toVariant().toMap(); if (!reply[QLatin1String("id")].toString().isEmpty()) { Choqok::NotifyManager::success(i18n("New post for account %1 submitted successfully.", theAccount->alias())); ret = 0; Q_EMIT postCreated(theAccount, post); } } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } if (ret) { Q_EMIT errorPost(theAccount, post, Choqok::MicroBlog::CommunicationError, i18n("Creating the new post failed. %1", job->errorString()), MicroBlog::Critical); } } void MastodonMicroBlog::slotFetchPost(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Account *theAccount = m_accountJobs.take(job); if (!theAccount) { qCDebug(CHOQOK) << "Account or postId is NULL pointer"; return; } int ret = 1; if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); } else { KIO::StoredTransferJob *j = qobject_cast(job); const QJsonDocument json = QJsonDocument::fromJson(j->data()); if (!json.isNull()) { const QVariantMap reply = json.toVariant().toMap(); MastodonPost *post = new MastodonPost; readPost(reply, post); ret = 0; Q_EMIT postFetched(theAccount, post); } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } if (ret) { Q_EMIT error(theAccount, Choqok::MicroBlog::CommunicationError, i18n("Cannot fetch post. %1", job->errorString()), MicroBlog::Critical); } } void MastodonMicroBlog::slotRemovePost(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Post *post = m_removePostJobs.take(job); Choqok::Account *theAccount = m_accountJobs.take(job); if (!post || !theAccount) { qCDebug(CHOQOK) << "Account or Post is NULL pointer"; return; } int ret = 1; if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); } else { KIO::TransferJob *j = qobject_cast(job); if (j->metaData().contains(QStringLiteral("responsecode"))) { int responseCode = j->queryMetaData(QStringLiteral("responsecode")).toInt(); if (responseCode == 200 || responseCode == 404) { ret = 0; Q_EMIT postRemoved(theAccount, post); } } } if (ret) { Q_EMIT errorPost(theAccount, post, Choqok::MicroBlog::CommunicationError, i18n("Removing the post failed. %1", job->errorString()), MicroBlog::Critical); } } void MastodonMicroBlog::slotUpdateTimeline(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Account *account = m_accountJobs.take(job); if (!account) { qCDebug(CHOQOK) << "Account or Post is NULL pointer"; return; } if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(account, Choqok::MicroBlog::CommunicationError, i18n("An error occurred when fetching the timeline")); } else { KIO::StoredTransferJob *j = qobject_cast(job); const QList list = readTimeline(j->data()); const QString timeline(m_timelinesRequests.take(job)); if (!list.isEmpty()) { setLastTimelineId(account, timeline, list.last()->conversationId); } Q_EMIT timelineDataReceived(account, timeline, list); } } void MastodonMicroBlog::fetchFollowers(MastodonAccount* theAccount, bool active) { qCDebug(CHOQOK); QUrl url(theAccount->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QStringLiteral("/api/v1/accounts/%1/followers").arg(theAccount->id())); QUrlQuery urlQuery; urlQuery.addQueryItem(QLatin1String("limit"), QLatin1String("80")); url.setQuery(urlQuery); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; return; } job->addMetaData(QLatin1String("customHTTPHeader"), authorizationMetaData(theAccount)); mJobsAccount[job] = theAccount; if (active) { connect(job, &KIO::StoredTransferJob::result, this, &MastodonMicroBlog::slotRequestFollowersScreenNameActive); } else { connect(job, &KIO::StoredTransferJob::result, this, &MastodonMicroBlog::slotRequestFollowersScreenNamePassive); } job->start(); Choqok::UI::Global::mainWindow()->showStatusMessage(i18n("Updating followers list for account %1...", theAccount->alias())); } void MastodonMicroBlog::slotRequestFollowersScreenNameActive(KJob* job) { finishRequestFollowersScreenName(job, true); } void MastodonMicroBlog::slotRequestFollowersScreenNamePassive(KJob* job) { finishRequestFollowersScreenName(job, false); } void MastodonMicroBlog::finishRequestFollowersScreenName(KJob *job, bool active) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::MicroBlog::ErrorLevel level = active ? Critical : Low; MastodonAccount *account = qobject_cast(mJobsAccount.take(job)); if (!account) { qCDebug(CHOQOK) << "Account or Post is NULL pointer"; return; } if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(account, ServerError, i18n("Followers list for account %1 could not be updated:\n%2", account->username(), job->errorString()), level); return; } else { KIO::StoredTransferJob *j = qobject_cast(job); const QByteArray buffer = j->data(); const QJsonDocument json = QJsonDocument::fromJson(buffer); if (!json.isNull()) { QStringList followers; for (const QVariant &user: json.array().toVariantList()) { followers.append(user.toMap()[QLatin1String("acct")].toString()); } account->setFollowers(followers); } else { QString err = i18n("Retrieving the followers list failed. The data returned from the server is corrupted."); qCDebug(CHOQOK) << "JSON parse error:the buffer is: \n" << buffer; Q_EMIT error(account, ParsingError, err, Critical); } } } void MastodonMicroBlog::fetchFollowing(MastodonAccount* theAccount, bool active) { qCDebug(CHOQOK); QUrl url(theAccount->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QStringLiteral("/api/v1/accounts/%1/following").arg(theAccount->id())); QUrlQuery urlQuery; urlQuery.addQueryItem(QLatin1String("limit"), QLatin1String("80")); url.setQuery(urlQuery); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; return; } job->addMetaData(QLatin1String("customHTTPHeader"), authorizationMetaData(theAccount)); mJobsAccount[job] = theAccount; if (active) { connect(job, &KIO::StoredTransferJob::result, this, &MastodonMicroBlog::slotRequestFollowingScreenNameActive); } else { connect(job, &KIO::StoredTransferJob::result, this, &MastodonMicroBlog::slotRequestFollowingScreenNamePassive); } job->start(); Choqok::UI::Global::mainWindow()->showStatusMessage(i18n("Updating following list for account %1...", theAccount->alias())); } void MastodonMicroBlog::slotRequestFollowingScreenNameActive(KJob* job) { finishRequestFollowingScreenName(job, true); } void MastodonMicroBlog::slotRequestFollowingScreenNamePassive(KJob* job) { finishRequestFollowingScreenName(job, false); } void MastodonMicroBlog::finishRequestFollowingScreenName(KJob *job, bool active) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::MicroBlog::ErrorLevel level = active ? Critical : Low; MastodonAccount *account = qobject_cast(mJobsAccount.take(job)); if (!account) { qCDebug(CHOQOK) << "Account or Post is NULL pointer"; return; } if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(account, ServerError, i18n("Following list for account %1 could not be updated:\n%2", account->username(), job->errorString()), level); return; } else { KIO::StoredTransferJob *j = qobject_cast(job); const QByteArray buffer = j->data(); const QJsonDocument json = QJsonDocument::fromJson(buffer); if (!json.isNull()) { QStringList following; for (const QVariant &user: json.array().toVariantList()) { following.append(user.toMap()[QLatin1String("acct")].toString()); } account->setFollowing(following); } else { QString err = i18n("Retrieving the following list failed. The data returned from the server is corrupted."); qCDebug(CHOQOK) << "JSON parse error:the buffer is: \n" << buffer; Q_EMIT error(account, ParsingError, err, Critical); } } } #include "mastodonmicroblog.moc" diff --git a/microblogs/mastodon/mastodonmicroblog.h b/microblogs/mastodon/mastodonmicroblog.h index d4308bce..dc6498d5 100644 --- a/microblogs/mastodon/mastodonmicroblog.h +++ b/microblogs/mastodon/mastodonmicroblog.h @@ -1,148 +1,148 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2017 Andrea Scarpino 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 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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/ */ #ifndef MASTODONMICROBLOG_H #define MASTODONMICROBLOG_H #include #include "microblog.h" class QUrl; class KJob; class MastodonAccount; class MastodonPost; class MastodonMicroBlog : public Choqok::MicroBlog { Q_OBJECT public: explicit MastodonMicroBlog(QObject *parent, const QVariantList &args); virtual ~MastodonMicroBlog(); virtual void aboutToUnload() override; virtual ChoqokEditAccountWidget *createEditAccountWidget(Choqok::Account *account, QWidget *parent) override; virtual Choqok::UI::ComposerWidget *createComposerWidget(Choqok::Account *account, QWidget *parent) override; virtual void createPost(Choqok::Account *theAccount, Choqok::Post *post) override; virtual Choqok::Account *createNewAccount(const QString &alias) override; virtual Choqok::UI::PostWidget *createPostWidget(Choqok::Account *account, Choqok::Post *post, QWidget *parent) override; virtual void fetchPost(Choqok::Account *theAccount, Choqok::Post *post) override; virtual QList loadTimeline(Choqok::Account *account, const QString &timelineName) override; virtual void removePost(Choqok::Account *theAccount, Choqok::Post *post) override; virtual QString generateRepeatedByUserTooltip(const QString &username) const; virtual QUrl profileUrl(Choqok::Account *account, const QString &username) const override; virtual void saveTimeline(Choqok::Account *account, const QString &timelineName, const QList< Choqok::UI::PostWidget * > &timeline) override; virtual Choqok::TimelineInfo *timelineInfo(const QString &timelineName) override; virtual void updateTimelines(Choqok::Account *theAccount) override; void createReply(Choqok::Account *theAccount, MastodonPost *post); void toggleReblog(Choqok::Account *theAccount, Choqok::Post *post); void toggleFavorite(Choqok::Account *theAccount, Choqok::Post *post); void fetchFollowers(MastodonAccount *theAccount, bool active); void fetchFollowing(MastodonAccount *theAccount, bool active); static QString userNameFromAcct(const QString &acct); static QString hostFromAcct(const QString &acct); Q_SIGNALS: void favorite(Choqok::Account *, Choqok::Post *); void followersUsernameListed(MastodonAccount *theAccount, const QStringList &friendsList); void followingUsernameListed(MastodonAccount *theAccount, const QStringList &friendsList); public Q_SLOTS: - virtual void showDirectMessageDialog(MastodonAccount *theAccount = 0, + virtual void showDirectMessageDialog(MastodonAccount *theAccount = nullptr, const QString &toUsername = QString()); void slotRequestFollowersScreenNameActive(KJob *job); void slotRequestFollowersScreenNamePassive(KJob *job); void slotRequestFollowingScreenNameActive(KJob *job); void slotRequestFollowingScreenNamePassive(KJob *job); protected Q_SLOTS: void slotCreatePost(KJob *job); void slotFavorite(KJob *job); void slotFetchPost(KJob *job); void slotReblog(KJob *job); void slotRemovePost(KJob *job); void slotUpdateTimeline(KJob *job); protected: static const QString homeTimeline; static const QString publicTimeline; static const QString favouritesTimeline; QString authorizationMetaData(MastodonAccount *account) const; QString lastTimelineId(Choqok::Account *theAccount, const QString &timeline) const; Choqok::Post *readPost(const QVariantMap &var, Choqok::Post *post); QList readTimeline(const QByteArray &buffer); void setLastTimelineId(Choqok::Account *theAccount, const QString &timeline, const QString &id); void setTimelinesInfo(); void finishRequestFollowersScreenName(KJob *job, bool active); void finishRequestFollowingScreenName(KJob *job, bool active); QMap m_accountJobs; QMap m_createPostJobs; QMap m_favoriteJobs; QMap m_removePostJobs; QMap m_shareJobs; QMap m_timelinesInfos; QHash > m_timelinesLatestIds; QMap mJobsAccount; QHash m_timelinesPaths; QMap m_timelinesRequests; private: class Private; Private *const d; }; #endif // MASTODONMICROBLOG_H diff --git a/microblogs/mastodon/mastodonoauth.cpp b/microblogs/mastodon/mastodonoauth.cpp index 007b9ae6..d1adb979 100644 --- a/microblogs/mastodon/mastodonoauth.cpp +++ b/microblogs/mastodon/mastodonoauth.cpp @@ -1,65 +1,65 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2017 Andrea Scarpino 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 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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 "mastodonoauth.h" #include #include #include #include "mastodonaccount.h" #include "mastodondebug.h" #include "mastodonoauthreplyhandler.h" MastodonOAuth::MastodonOAuth(MastodonAccount *account) : QOAuth2AuthorizationCodeFlow(account), - m_replyHandler(0), m_networkAccessManager(0) + m_replyHandler(nullptr), m_networkAccessManager(nullptr) { qCDebug(CHOQOK); m_replyHandler = new MastodonOAuthReplyHandler(this); setReplyHandler(m_replyHandler); m_networkAccessManager = new KIO::AccessManager(this); setNetworkAccessManager(m_networkAccessManager); setClientIdentifier(account->consumerKey()); setClientIdentifierSharedKey(account->consumerSecret()); setScope(QLatin1String("read write follow")); setAccessTokenUrl(QUrl(account->host() + QLatin1String("/oauth/token"))); setAuthorizationUrl(QUrl(account->host() + QLatin1String("/oauth/authorize"))); } MastodonOAuth::~MastodonOAuth() { m_replyHandler->deleteLater(); m_networkAccessManager->deleteLater(); } void MastodonOAuth::getToken(const QString &code) { requestAccessToken(code); } diff --git a/microblogs/mastodon/mastodonpostwidget.h b/microblogs/mastodon/mastodonpostwidget.h index 3457ec58..0cecf4e7 100644 --- a/microblogs/mastodon/mastodonpostwidget.h +++ b/microblogs/mastodon/mastodonpostwidget.h @@ -1,60 +1,60 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2017 Andrea Scarpino 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 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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/ */ #ifndef MASTODONPOSTWIDGET_H #define MASTODONPOSTWIDGET_H #include "postwidget.h" class MastodonPostWidget : public Choqok::UI::PostWidget { Q_OBJECT public: - explicit MastodonPostWidget(Choqok::Account *account, Choqok::Post *post, QWidget *parent = 0); + explicit MastodonPostWidget(Choqok::Account *account, Choqok::Post *post, QWidget *parent = nullptr); virtual ~MastodonPostWidget(); virtual QString generateSign() override; virtual void initUi() override; protected Q_SLOTS: virtual void slotResendPost() override; void slotToggleFavorite(Choqok::Account *, Choqok::Post *); void slotReply(); void slotWriteTo(); void slotReplyToAll(); void toggleFavorite(); protected: virtual QString getUsernameHyperlink(const Choqok::User &user) const; static const QIcon unFavIcon; private: void updateFavStat(); class Private; Private *const d; }; #endif // MASTODONPOSTWIDGET_H