File indexing completed on 2024-05-12 05:04:09

0001 // SPDX-FileCopyrightText: 2021 Carl Schwan <carl@carlschwan.eu>
0002 // SPDX-License-Identifier: GPL-3.0-or-later
0003 
0004 #include "identity.h"
0005 
0006 #include "abstractaccount.h"
0007 #include "relationship.h"
0008 
0009 using namespace Qt::Literals::StringLiterals;
0010 
0011 QString Identity::displayName() const
0012 {
0013     return !m_displayName.isEmpty() ? m_displayName : m_username;
0014 }
0015 
0016 QString Identity::username() const
0017 {
0018     return m_username;
0019 }
0020 
0021 QString Identity::bio() const
0022 {
0023     return m_bio;
0024 }
0025 
0026 QString Identity::account() const
0027 {
0028     return m_account;
0029 }
0030 
0031 bool Identity::locked() const
0032 {
0033     return m_locked;
0034 }
0035 
0036 QString Identity::visibility() const
0037 {
0038     return m_visibility;
0039 }
0040 
0041 QUrl Identity::avatarUrl() const
0042 {
0043     return m_avatarUrl;
0044 }
0045 
0046 QUrl Identity::backgroundUrl() const
0047 {
0048     return m_backgroundUrl;
0049 }
0050 
0051 int Identity::followersCount() const
0052 {
0053     return m_followersCount;
0054 }
0055 
0056 int Identity::followingCount() const
0057 {
0058     return m_followingCount;
0059 }
0060 
0061 int Identity::statusesCount() const
0062 {
0063     return m_statusesCount;
0064 }
0065 
0066 int Identity::permission() const
0067 {
0068     return m_permission;
0069 }
0070 
0071 QJsonArray Identity::fields() const
0072 {
0073     return m_fields;
0074 }
0075 
0076 Relationship *Identity::relationship() const
0077 {
0078     return m_relationship;
0079 }
0080 
0081 void Identity::setRelationship(Relationship *r)
0082 {
0083     if (m_relationship == r) {
0084         return;
0085     }
0086 
0087     // delete old relationship object if we receive a new one
0088     delete m_relationship;
0089 
0090     m_relationship = r;
0091     Q_EMIT relationshipChanged();
0092 }
0093 
0094 void Identity::reparentIdentity(AbstractAccount *parent)
0095 {
0096     m_parent = parent;
0097 }
0098 
0099 void Identity::fromSourceData(const QJsonObject &doc)
0100 {
0101     m_id = doc["id"_L1].toString();
0102     m_displayName = doc["display_name"_L1].toString();
0103     m_username = doc["username"_L1].toString();
0104     m_account = doc["acct"_L1].toString();
0105     m_bio = doc["note"_L1].toString();
0106     m_locked = doc["locked"_L1].toBool();
0107     m_backgroundUrl = QUrl(doc["header"_L1].toString());
0108     m_avatarUrl = QUrl(doc["avatar"_L1].toString());
0109     m_followersCount = doc["followers_count"_L1].toInt();
0110     m_followingCount = doc["following_count"_L1].toInt();
0111     m_statusesCount = doc["statuses_count"_L1].toInt();
0112     m_fields = doc["fields"_L1].toArray();
0113     m_url = QUrl(doc["url"_L1].toString());
0114     m_permission = doc["role"_L1]["permissions"_L1].toString().toInt();
0115     // When the user data is ourselves, we get source.privacy
0116     // with the default post privacy setting for the user. all others
0117     // will get empty strings.
0118     QJsonObject source = doc["source"_L1].toObject();
0119     m_visibility = source["privacy"_L1].toString();
0120 
0121     m_displayNameHtml = m_displayName.replace(QLatin1Char('<'), QStringLiteral("&lt;")).replace(QLatin1Char('>'), QStringLiteral("&gt;"));
0122 
0123     const auto emojis = CustomEmoji::parseCustomEmojis(doc["emojis"_L1].toArray());
0124 
0125     m_displayNameHtml = CustomEmoji::replaceCustomEmojis(emojis, m_displayNameHtml);
0126     m_bio = CustomEmoji::replaceCustomEmojis(emojis, m_bio);
0127 
0128     const QString baseUrl = m_url.toDisplayString(QUrl::RemovePath);
0129 
0130     // Attempt to replace the tag URLs with proper ones, although this should really be handled by the Mastodon API
0131     m_bio = m_bio.replace(baseUrl + QStringLiteral("/tags/"), QStringLiteral("hashtag:/"), Qt::CaseInsensitive);
0132 
0133     // Even worse, mentions are not given proper ids so we must figure it out on our own.
0134     // The account could be on a different server, so let's take advantage of web+ap and use that
0135     // to search for the account!
0136     // TODO: Mentions have a specific CSS class in the HTML, maybe we can use that instead of dirty regex?
0137     static QRegularExpression re(QStringLiteral(R"((?:href="?)(?:https?|ftp):\S[^"]+)"));
0138     const auto match = re.match(m_bio);
0139     if (re.isValid()) {
0140         for (int i = 0; i <= match.lastCapturedIndex(); ++i) {
0141             const int start = match.capturedStart(i);
0142             const int length = match.capturedLength(i);
0143             const QString captured = match.captured(i);
0144             if (captured.contains('@'_L1)) {
0145                 // The length of "href=" which is used in the regex.
0146                 const int hrefLength = 6;
0147                 m_bio = m_bio.replace(start + hrefLength, length - hrefLength, QStringLiteral("web+ap:/") + captured.mid(hrefLength));
0148             }
0149         }
0150     }
0151 
0152     Q_EMIT identityUpdated();
0153 }
0154 
0155 QString Identity::id() const
0156 {
0157     return m_id;
0158 }
0159 
0160 QString Identity::displayNameHtml() const
0161 {
0162     return !m_displayNameHtml.isEmpty() ? m_displayNameHtml : m_username;
0163 }
0164 
0165 QUrl Identity::url() const
0166 {
0167     return m_url;
0168 }
0169 
0170 #include "moc_identity.cpp"