aboutsummaryrefslogtreecommitdiffstats
path: root/src/list_item.h
diff options
context:
space:
mode:
authorConfuSomu2023-07-18 00:12:58 +0200
committerConfuSomu2023-07-18 00:12:58 +0200
commitcdd08523b9af7afda906766d22197a066c9264f3 (patch)
tree4944566510ad446d49dbab8cb34d95a820d03881 /src/list_item.h
parent5ed7d9b53a65aec1f4793f62ac15195c44224b39 (diff)
downloadActorViewer-cdd08523b9af7afda906766d22197a066c9264f3.tar
ActorViewer-cdd08523b9af7afda906766d22197a066c9264f3.tar.gz
ActorViewer-cdd08523b9af7afda906766d22197a066c9264f3.zip
Move APAttachmentFields to fields.h
Finish consolidating every AP…Field in one file to avoid circular include dependencies which are very hard/impossible to work with.
Diffstat (limited to 'src/list_item.h')
0 files changed, 0 insertions, 0 deletions
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
#include "mastodon_instance.h"
#include "src/activitypub/appost.h"
#include "src/activitypub/apquestion.h"
#include "src/settings_interface.h"
#include "src/types.h"

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QUrl>
#include <QDebug>

APPost* post_from_json(const QJsonObject &status);

MastodonInstance::MastodonInstance() : instance(SettingsInterface::quick_read_setting<QString>("net/instance/address").toStdString(), SettingsInterface::quick_read_setting<QString>("net/instance/token").toStdString()), connection(instance) {

}

MastodonInstance::~MastodonInstance() {
    if (obtain_token)
        delete obtain_token;
}

QString MastodonInstance::oauth2_step1() {
    obtain_token = new mastodonpp::Instance::ObtainToken{instance};
    auto answer{obtain_token->step_1("ActorViewer", "read", "https://twilightsparkle.space")};
    if (answer)
        return answer.body.c_str();
    else
        return "";
}

Instance::OAuth2Step2 MastodonInstance::oauth2_step2(const QString &auth_code) {
    if (!obtain_token) return {false};
    auto answer{obtain_token->step_2(auth_code.toStdString())};
    QString token;

    if (answer) {
        token = answer.body.c_str();
    }

    delete obtain_token; obtain_token = nullptr;
    return {(bool)answer, token};
}

APPost* MastodonInstance::get_post_from_url(const QString &url) {
    auto answer{connection.get(mastodonpp::API::v2::search, {
        {"q", QUrl::toPercentEncoding(url).toStdString()},
        {"type", "statuses"},
        {"limit", "1"},
        {"resolve", "true"}
    })};

    if (answer) {
        QJsonDocument doc = QJsonDocument::fromJson(answer.body.c_str());
        QJsonObject obj = doc.object();
        qDebug() << doc;
        if (obj.contains("statuses")) {
            QJsonObject status = obj["statuses"].toArray().first().toObject();
            if (status.isEmpty()) return new APPost({.content="invalid"}); // Invalid
            return post_from_json(status);
        }
    }

    return new APPost({.content="connection error"});
}

// Create a filled APPost object from a Status entity (https://docs.joinmastodon.org/entities/Status/)
// We have to return a pointer as else I can't get derived classes of APPost to render properly: the additional methods are ignored.
// Furthermore, using pointers removes unecessary copying, even if that can be reduced by return value optimization.
APPost* post_from_json(const QJsonObject &status) {
    APObjectFields fields;
    bool is_question = status.contains("poll");

    fields.by_actor = status["account"]["url"].toString();
    fields.reply_to_url = status["in_reply_to_id"].toString(); // id ≠ url

    fields.languages.append(status["language"].toString());
    fields.published = status["created_at"].toString();

    fields.object_url = status["uri"].toString();
    fields.web_url = status["url"].toString();

    if (status["sensitive"].toBool(true))
        fields.summary = status["spoiler_text"].toString();
    if (status.contains("content"))
        fields.content = status["content"].toString();

    if (status.contains("visibility")) {
        QString visibility = status["visibility"].toString();
        if (visibility == "public") fields.visibility = StatusType::PUBLIC;
        else if (visibility == "unlisted") fields.visibility = StatusType::UNLISTED;
        else if (visibility == "private") fields.visibility = StatusType::PRIVATE;
        else if (visibility == "direct") fields.visibility = StatusType::DIRECT;
        else fields.visibility = StatusType::UNKNOWN;
    }

    if (QJsonArray medias = status["media_attachments"].toArray(); not medias.isEmpty()) {
        for (QJsonValueRef media : medias) {
            if (not media.isObject()) continue;
            QJsonObject attrib = media.toObject();
            fields.attachments.push_back({
                // FIXME: we use the preview to lower bandwidth but it would be nicer to have APAttachment fields for differencing between qualities.
                .path = attrib["preview_url"].toString(),
                // FIXME: we don't have any better attribute to work with
                .filename = attrib["id"].toString(),
                .media_type = attrib["type"].toString(),
                .name = attrib["description"].toString()
                // TODO: we don't use the blurhash yet…
            });
        }
    }

    if (is_question) {
        QJsonObject poll = status["poll"].toObject();

        fields.question.end_time = poll["expires_at"].toString();
        fields.question.closed_time = poll["expires_at"].toString();
        fields.question.total_votes = poll["votes_count"].toInt();

        for (QJsonValueRef option : poll["options"].toArray()) {
            QJsonObject element = option.toObject();
            fields.question.poll_options.push_back({element["title"].toString(), element["votes_count"].toInt()});
        }


        // TODO: have an boolean attribute for defining if the poll is multiple choice or not, int for the voters_count and bool/int for `voted` and `own_votes`
    }

    if (is_question)
        return new APQuestion(fields);
    else
        return new APPost(fields);
}