File indexing completed on 2024-05-05 04:57:14

0001 /*
0002     This file is part of Choqok, the KDE micro-blogging client
0003 
0004     SPDX-FileCopyrightText: 2008-2012 Mehrdad Momeny <mehrdad.momeny@gmail.com>
0005 
0006     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0007 */
0008 
0009 #include "gnusocialapipostwidget.h"
0010 
0011 #include <QAction>
0012 #include <QMenu>
0013 #include <QPushButton>
0014 
0015 #include <KLocalizedString>
0016 
0017 #include "choqokbehaviorsettings.h"
0018 #include "choqoktools.h"
0019 #include "notifymanager.h"
0020 #include "quickpost.h"
0021 
0022 #include "twitterapiaccount.h"
0023 #include "twitterapimicroblog.h"
0024 #include "twitterapiwhoiswidget.h"
0025 
0026 #include "gnusocialapiaccount.h"
0027 #include "gnusocialapiconversationtimelinewidget.h"
0028 #include "gnusocialapidebug.h"
0029 #include "gnusocialapimicroblog.h"
0030 #include "gnusocialapisearch.h"
0031 
0032 const QRegExp GNUSocialApiPostWidget::mGroupRegExp(QLatin1String("([\\s]|^)!([a-z0-9]+){1,64}"),  Qt::CaseInsensitive);
0033 const QRegExp GNUSocialApiPostWidget::mGNUSocialApiUserRegExp(QLatin1String("([\\s\\W]|^)@([a-z0-9_]+){1,64}(?!(@))"), Qt::CaseInsensitive);
0034 const QRegExp GNUSocialApiPostWidget::mGNUSocialApiHashRegExp(QLatin1String("([\\s]|^)#([\\w_\\.\\-]+)"), Qt::CaseInsensitive);
0035 
0036 const QString subdomains = QLatin1String("(([a-z0-9-_]\\.)?)");
0037 const QString dname = QLatin1String("(([a-z0-9-\\x0080-\\xFFFF]){1,63}\\.)+");
0038 const QString zone = QLatin1String("((a[cdefgilmnoqrstuwxz])|(b[abdefghijlmnorstvwyz])|(c[acdfghiklmnoruvxyz])|(d[ejkmoz])|(e[ceghrstu])|\
0039 (f[ijkmor])|(g[abdefghilmnpqrstuwy])|(h[kmnrtu])|(i[delmnoqrst])|(j[emop])|(k[eghimnprwyz])|(l[abcikrstuvy])|\
0040 (m[acdefghklmnopqrstuvwxyz])|(n[acefgilopruz])|(om)|(p[aefghklnrstwy])|(qa)|(r[eosuw])|(s[abcdeghijklmnortuvyz])|\
0041 (t[cdfghjkmnoprtvwz])|(u[agksyz])|(v[aceginu])|(w[fs])|(ye)|(z[amrw])\
0042 |(asia|com|info|net|org|biz|name|pro|aero|cat|coop|edu|jobs|mobi|museum|tel|travel|gov|int|mil|local)|(中国)|(公司)|(网络)|(صر)|(امارات)|(рф))");
0043 const QString domain = QLatin1Char('(') + subdomains + dname + zone + QLatin1Char(')');
0044 const QRegExp GNUSocialApiPostWidget::mStatusNetUserRegExp(QLatin1String("([\\s\\W]|^)@(([a-z0-9]+){1,64}@") + domain + QLatin1Char(')'), Qt::CaseInsensitive);
0045 
0046 class GNUSocialApiPostWidget::Private
0047 {
0048 public:
0049     Private(Choqok::Account *theAccount)
0050     {
0051         account = qobject_cast<GNUSocialApiAccount *>(theAccount);
0052         mBlog = qobject_cast<GNUSocialApiMicroBlog *>(account->microblog());
0053     }
0054     GNUSocialApiAccount *account;
0055     GNUSocialApiMicroBlog *mBlog;
0056     QString tmpUsername;
0057 };
0058 
0059 GNUSocialApiPostWidget::GNUSocialApiPostWidget(Choqok::Account *account, Choqok::Post *post, QWidget *parent)
0060     : TwitterApiPostWidget(account, post, parent), d(new Private(account))
0061 {
0062 
0063 }
0064 
0065 void GNUSocialApiPostWidget::initUi()
0066 {
0067     TwitterApiPostWidget::initUi();
0068 
0069     QPushButton *btn = buttons().value(QLatin1String("btnResend"));
0070 
0071     if (btn) {
0072         QMenu *menu = new QMenu(btn);
0073         QAction *resend = new QAction(i18n("Manual ReSend"), menu);
0074         connect(resend, &QAction::triggered, this, &GNUSocialApiPostWidget::slotResendPost);
0075         QAction *repeat = new QAction(i18n("Repeat"), menu);
0076         repeat->setToolTip(i18n("Repeat post using API"));
0077         connect(repeat, &QAction::triggered, this, &GNUSocialApiPostWidget::repeatPost);
0078         menu->addAction(repeat);
0079         menu->addAction(resend);
0080         btn->setMenu(menu);
0081     }
0082 }
0083 
0084 GNUSocialApiPostWidget::~GNUSocialApiPostWidget()
0085 {
0086     delete d;
0087 }
0088 
0089 void GNUSocialApiPostWidget::slotReplyToAll()
0090 {
0091     QStringList nicks;
0092     nicks.append(currentPost()->author.userName);
0093 
0094     QString txt = QStringLiteral("@%1 ").arg(currentPost()->author.userName);
0095 
0096     int pos = 0;
0097     while ((pos = mGNUSocialApiUserRegExp.indexIn(currentPost()->content, pos)) != -1) {
0098         if (mGNUSocialApiUserRegExp.cap(2).toLower() != currentAccount()->username() &&
0099                 mGNUSocialApiUserRegExp.cap(2).toLower() != currentPost()->author.userName &&
0100                 !nicks.contains(mGNUSocialApiUserRegExp.cap(2).toLower())) {
0101             nicks.append(mGNUSocialApiUserRegExp.cap(2));
0102             txt += QStringLiteral("@%1 ").arg(mGNUSocialApiUserRegExp.cap(2));
0103         }
0104         pos += mGNUSocialApiUserRegExp.matchedLength();
0105     }
0106 
0107     txt.chop(1);
0108 
0109     Q_EMIT reply(txt, currentPost()->postId, currentPost()->author.userName);
0110 }
0111 
0112 QString GNUSocialApiPostWidget::prepareStatus(const QString &text)
0113 {
0114     QString res = TwitterApiPostWidget::prepareStatus(text);
0115     res.replace(mStatusNetUserRegExp, QLatin1String("\\1@<a href='user://\\2'>\\2</a>"));
0116     res.replace(mGNUSocialApiUserRegExp, QLatin1String("\\1@<a href='user://\\2'>\\2</a>"));
0117     res.replace(mGroupRegExp, QLatin1String("\\1!<a href='group://\\2'>\\2</a>"));
0118     res.replace(mGNUSocialApiHashRegExp, QLatin1String("\\1#<a href='tag://\\2'>\\2</a>"));
0119 
0120     return res;
0121 }
0122 
0123 QString GNUSocialApiPostWidget::generateSign()
0124 {
0125     return TwitterApiPostWidget::generateSign();
0126 }
0127 
0128 void GNUSocialApiPostWidget::checkAnchor(const QUrl &url)
0129 {
0130     QString scheme = url.scheme();
0131     QAction *ret;
0132     if (scheme == QLatin1String("tag")) {
0133         QString unpcode = QUrl::fromAce(url.host().toUtf8());
0134         unpcode.remove(QLatin1Char('.'));
0135         unpcode.remove(QLatin1Char('-'));
0136         unpcode.remove(QLatin1Char('_'));
0137 
0138         QMenu menu;
0139         QAction *search = new QAction(QIcon::fromTheme(QLatin1String("system-search")),
0140                                       i18n("Search for %1", unpcode), &menu);
0141         QAction *openInBrowser = new QAction(QIcon::fromTheme(QLatin1String("internet-services")),
0142                                              i18n("Open tag page in browser"), &menu);
0143         menu.addAction(search);
0144         menu.addAction(openInBrowser);
0145         menu.setDefaultAction(search);
0146         ret = menu.exec(QCursor::pos());
0147         if (ret == search) {
0148             d->mBlog->searchBackend()->requestSearchResults(currentAccount(),
0149                     unpcode,
0150                     GNUSocialApiSearch::ReferenceHashtag);
0151         } else if (ret == openInBrowser) {
0152             Choqok::openUrl(QUrl(d->account->homepageUrl().toDisplayString() +
0153                                  QLatin1String("/tag/") + unpcode));
0154         }
0155     } else if (scheme == QLatin1String("group")) {
0156         QMenu menu;
0157         QAction *search = new QAction(QIcon::fromTheme(QLatin1String("system-search")),
0158                                       i18n("Show latest group posts"), &menu);
0159         QAction *openInBrowser = new QAction(QIcon::fromTheme(QLatin1String("applications-internet")),
0160                                              i18n("Open group page in browser"), &menu);
0161         menu.addAction(search);
0162         menu.addAction(openInBrowser);
0163         menu.setDefaultAction(search);
0164         ret = menu.exec(QCursor::pos());
0165         if (ret == search) {
0166             d->mBlog->searchBackend()->requestSearchResults(currentAccount(),
0167                     url.host(),
0168                     GNUSocialApiSearch::ReferenceGroup);
0169         } else if (ret == openInBrowser) {
0170             Choqok::openUrl(QUrl(d->account->homepageUrl().toDisplayString() +
0171                                  QLatin1String("/group/") + url.host()));
0172         }
0173     } else if (scheme == QLatin1String("user")) {
0174         QString username = (url.userName().isEmpty() ? QString() : QStringLiteral("%1@").arg(url.userName())) +
0175                            url.host();
0176         QMenu menu;
0177         QAction *info = new QAction(QIcon::fromTheme(QLatin1String("user-identity")), i18nc("Who is user", "Who is %1",
0178                                     username), &menu);
0179         QAction *from = new QAction(QIcon::fromTheme(QLatin1String("edit-find-user")), i18nc("Posts from user", "Posts from %1",
0180                                     username), &menu);
0181         QAction *to = new QAction(QIcon::fromTheme(QLatin1String("meeting-attending")), i18nc("Replies to user", "Replies to %1",
0182                                   username), &menu);
0183         QAction *openInBrowser = new QAction(QIcon::fromTheme(QLatin1String("applications-internet")),
0184                                              i18nc("Open profile page in browser",
0185                                                      "Open profile in browser"), &menu);
0186         menu.addAction(info);
0187         if (currentPost()->source != QLatin1String("ostatus")) {
0188             menu.addAction(from);
0189             menu.addAction(to);
0190             from->setData(GNUSocialApiSearch::FromUser);
0191             to->setData(GNUSocialApiSearch::ToUser);
0192         }
0193         menu.addAction(openInBrowser);
0194 
0195         //Subscribe/UnSubscribe/Block
0196         bool isSubscribe = false;
0197         QString accountUsername = d->account->username().toLower();
0198         QString postUsername = username.toLower();
0199         QAction *subscribe = nullptr, *block = nullptr, *replyTo = nullptr, *dMessage = nullptr;
0200         if (accountUsername != postUsername) {
0201             menu.addSeparator();
0202             QMenu *actionsMenu = menu.addMenu(QIcon::fromTheme(QLatin1String("applications-system")), i18n("Actions"));
0203             replyTo = new QAction(QIcon::fromTheme(QLatin1String("edit-undo")), i18nc("Write a message to user attention", "Write to %1",
0204                                   username), actionsMenu);
0205             actionsMenu->addAction(replyTo);
0206             if (d->account->friendsList().contains(username)) {
0207                 dMessage = new QAction(QIcon::fromTheme(QLatin1String("mail-message-new")), i18nc("Send direct message to user",
0208                                        "Send private message to %1",
0209                                        username), actionsMenu);
0210                 actionsMenu->addAction(dMessage);
0211                 isSubscribe = false;//It's UnSubscribe
0212                 subscribe = new QAction(QIcon::fromTheme(QLatin1String("list-remove-user")),
0213                                         i18nc("Unsubscribe from user",
0214                                               "Unsubscribe from %1", username), actionsMenu);
0215             } else {
0216                 isSubscribe = true;
0217                 subscribe = new QAction(QIcon::fromTheme(QLatin1String("list-add-user")),
0218                                         i18nc("Subscribe to user",
0219                                               "Subscribe to %1", username), actionsMenu);
0220             }
0221             block = new QAction(QIcon::fromTheme(QLatin1String("dialog-cancel")),
0222                                 i18nc("Block user",
0223                                       "Block %1", username), actionsMenu);
0224             if (currentPost()->source != QLatin1String("ostatus")) {
0225                 actionsMenu->addAction(subscribe);
0226                 actionsMenu->addAction(block);
0227             }
0228         }
0229         ret = menu.exec(QCursor::pos());
0230         if (ret == nullptr) {
0231             return;
0232         }
0233         if (ret == info) {
0234             TwitterApiWhoisWidget *wd = new TwitterApiWhoisWidget(d->account, username, *currentPost(), this);
0235             wd->show(QCursor::pos());
0236             return;
0237         } else if (ret == subscribe) {
0238             if (isSubscribe) {
0239                 d->mBlog->createFriendship(d->account, username);
0240             } else {
0241                 d->mBlog->destroyFriendship(d->account, username);
0242             }
0243             return;
0244         } else if (ret == block) {
0245             d->mBlog->blockUser(d->account, username);
0246             return;
0247         } else if (ret == openInBrowser) {
0248             Choqok::openUrl(currentAccount()->microblog()->profileUrl(currentAccount(), username));
0249             return;
0250         } else if (ret == replyTo) {
0251             Q_EMIT reply(QStringLiteral("@%1").arg(username), QString(), username);
0252             return;
0253         } else if (ret == dMessage) {
0254             d->mBlog->showDirectMessageDialog(d->account, username);
0255             return;
0256         }
0257         int type = ret->data().toInt();
0258         d->mBlog->searchBackend()->requestSearchResults(currentAccount(),
0259                 url.host(),
0260                 type);
0261     } else if (scheme == QLatin1String("conversation")) {
0262         GNUSocialApiConversationTimelineWidget *tm = new GNUSocialApiConversationTimelineWidget(currentAccount(),
0263                 url.host());
0264         connect(tm, &GNUSocialApiConversationTimelineWidget::forwardReply, this, &GNUSocialApiPostWidget::reply);
0265         connect(tm, &GNUSocialApiConversationTimelineWidget::forwardResendPost, this, &GNUSocialApiPostWidget::resendPost);
0266         tm->show();
0267     } else {
0268         TwitterApiPostWidget::checkAnchor(url);
0269     }
0270 }
0271 
0272 void GNUSocialApiPostWidget::slotResendPost()
0273 {
0274     QString text = generateResendText();
0275 
0276     if (d->account->isChangeExclamationMark()) {
0277         int index = 0;
0278         while (true) {
0279             index = mGroupRegExp.indexIn(text, index);
0280             if (index != -1) {
0281                 text.replace(index + 1, 1, d->account->changeExclamationMarkToText());
0282             } else {
0283                 break;
0284             }
0285         }
0286     }
0287 
0288     if ((Choqok::BehaviorSettings::resendWithQuickPost() || currentAccount()->isReadOnly()) &&
0289             Choqok::UI::Global::quickPostWidget()) {
0290         Choqok::UI::Global::quickPostWidget()->setText(text);
0291     } else {
0292         Q_EMIT resendPost(text);
0293     }
0294 }