This commit is contained in:
Martin Rotter 2023-12-11 10:44:24 +01:00
parent aa7b18827c
commit 6b9041a110
13 changed files with 104 additions and 32 deletions

@ -1 +1 @@
Subproject commit 2b41d67a372b6ce42ed666e7d88e7815694f1966
Subproject commit b874b2fad4fcb91861b62ae2a52df44efac98ddd

View File

@ -275,10 +275,6 @@ QList<Feed*> FeedsModel::feedsForScheduledUpdate(bool auto_update_now) {
return feeds_for_update;
}
QList<Message> FeedsModel::messagesForItem(RootItem* item) const {
return item->undeletedMessages();
}
int FeedsModel::columnCount(const QModelIndex& parent) const {
Q_UNUSED(parent)
return FEEDS_VIEW_COLUMN_COUNT;

View File

@ -54,11 +54,6 @@ class RSSGUARD_DLLSPEC FeedsModel : public QAbstractItemModel {
// This method might change some properties of some feeds.
QList<Feed*> feedsForScheduledUpdate(bool auto_update_now);
// Returns (undeleted) messages for given feeds.
// This is usually used for displaying whole feeds
// in "newspaper" mode.
QList<Message> messagesForItem(RootItem* item) const;
// Returns ALL RECURSIVE CHILD feeds contained within single index.
QList<Feed*> feedsForIndex(const QModelIndex& index = QModelIndex()) const;

View File

@ -164,6 +164,14 @@ void Message::sanitize(const Feed* feed, bool fix_future_datetimes) {
}
}
QJsonObject Message::toJson() const {
QJsonObject obj;
obj.insert(QSL("contents"), m_contents);
return obj;
}
Message Message::fromSqlRecord(const QSqlRecord& record, bool* result) {
if (record.count() != MSG_DB_LABELS_IDS + 1) {
if (result != nullptr) {

View File

@ -3,7 +3,7 @@
#ifndef MESSAGE_H
#define MESSAGE_H
//#include "definitions/definitions.h"
// #include "definitions/definitions.h"
#include <QDataStream>
#include <QDateTime>
@ -56,6 +56,8 @@ class RSSGUARD_DLLSPEC Message {
void sanitize(const Feed* feed, bool fix_future_datetimes);
QJsonObject toJson() const;
// Creates Message from given record, which contains
// row from query SELECT * FROM Messages WHERE ....;
static Message fromSqlRecord(const QSqlRecord& record, bool* result = nullptr);

View File

@ -1174,6 +1174,55 @@ QList<Message> DatabaseQueries::getUndeletedUnreadMessages(const QSqlDatabase& d
return messages;
}
QList<Message> DatabaseQueries::getFeedsSlice(const QSqlDatabase& db,
const QString& feed_custom_id,
int account_id,
bool newest_first,
bool unread_only,
int row_offset,
int row_limit) {
QList<Message> messages;
QSqlQuery q(db);
q.setForwardOnly(true);
q.prepare(QSL("SELECT %1 "
"FROM Messages "
"WHERE is_deleted = 0 AND is_pdeleted = 0 AND "
" is_read = :is_read "
" feed = :feed AND account_id = :account_id "
"ORDER BY Messages.date_created %2 "
"LIMIT :row_limit OFFSET :row_offset;")
.arg(messageTableAttributes(true, db.driverName() == QSL(APP_DB_SQLITE_DRIVER)).values().join(QSL(", ")),
newest_first ? QSL("DESC") : QSL("ASC")));
q.bindValue(QSL(":feed"), feed_custom_id);
q.bindValue(QSL(":account_id"), account_id);
q.bindValue(QSL(":row_limit"), row_limit);
q.bindValue(QSL(":row_offset"), row_offset);
if (unread_only) {
q.bindValue(QSL(":is_read"), 0);
}
else {
q.bindValue(QSL(":is_read"), QSL("is_read"));
}
if (q.exec()) {
while (q.next()) {
bool decoded;
Message message = Message::fromSqlRecord(q.record(), &decoded);
if (decoded) {
messages.append(message);
}
}
}
else {
throw ApplicationException(q.lastError().driverText());
}
return messages;
}
QList<Message> DatabaseQueries::getUndeletedMessagesForFeed(const QSqlDatabase& db,
const QString& feed_custom_id,
int account_id,

View File

@ -118,6 +118,14 @@ class DatabaseQueries {
static QList<Message> getUndeletedMessagesForBin(const QSqlDatabase& db, int account_id, bool* ok = nullptr);
static QList<Message> getUndeletedMessagesForAccount(const QSqlDatabase& db, int account_id, bool* ok = nullptr);
static QList<Message> getFeedsSlice(const QSqlDatabase& db,
const QString& feed_custom_id,
int account_id,
bool newest_first,
bool unread_only,
int row_offset,
int row_limit);
// Custom ID accumulators.
static QStringList bagOfMessages(const QSqlDatabase& db, ServiceRoot::BagOfMessages bag, const Feed* feed);
static QHash<QString, QStringList> bagsOfMessages(const QSqlDatabase& db, const QList<Label*>& labels);

View File

@ -11,7 +11,7 @@
ApiServer::ApiServer(QObject* parent) : HttpServer(parent) {}
void ApiServer::answerClient(QTcpSocket* socket, const QHttpRequest& request) {
void ApiServer::answerClient(QTcpSocket* socket, const HttpRequest& request) {
QByteArray incoming_data = socket->readAll();
QByteArray output_data;
@ -26,9 +26,17 @@ void ApiServer::answerClient(QTcpSocket* socket, const QHttpRequest& request) {
}
else {
ApiRequest req(incoming_doc);
ApiResponse resp(processRequest(req));
output_data = resp.toJson().toJson();
try {
ApiResponse resp(processRequest(req));
output_data = resp.toJson().toJson();
}
catch (const ApplicationException& ex) {
ApiResponse err_resp(ApiResponse::Result::Error, req.m_method, ex.message());
output_data = err_resp.toJson().toJson();
}
}
const QByteArray reply_message = QSL("HTTP/1.0 200 OK \r\n"
@ -63,17 +71,23 @@ ApiResponse ApiServer::processAppVersion() const {
ApiResponse ApiServer::processArticlesFromFeed(const QJsonValue& req) const {
QJsonObject data = req.toObject();
QString feed_id = data.value(QSL("feed")).toString();
int account_id = data.value(QSL("account")).toInt();
bool newest_first = data.value(QSL("newest_first")).toBool();
bool unread_only = data.value(QSL("unread_only")).toBool();
int row_offset = data.value(QSL("row_offset")).toInt();
int row_limit = data.value(QSL("row_limit")).toInt();
QSqlDatabase database = qApp->database()->driver()->connection(metaObject()->className());
QList<Message> msgs = DatabaseQueries::getUndeletedMessagesForFeed(database, feed_id, account_id);
QList<Message> msgs =
DatabaseQueries::getFeedsSlice(database, feed_id, account_id, newest_first, unread_only, row_offset, row_limit);
QJsonArray msgs_json_array;
for (const Message& msg : msgs) {
QJsonObject msg_obj;
msg_obj.insert(QSL("contents"), msg.m_contents);
msg_obj.insert(QSL("contents"), msg.toJson());
msgs_json_array.append(msg_obj);
}

View File

@ -45,7 +45,7 @@ class ApiServer : public HttpServer {
explicit ApiServer(QObject* parent = nullptr);
protected:
virtual void answerClient(QTcpSocket* socket, const QHttpRequest& request);
virtual void answerClient(QTcpSocket* socket, const HttpRequest& request);
private:
ApiResponse processRequest(const ApiRequest& req) const;

View File

@ -79,28 +79,28 @@ void HttpServer::readReceivedData(QTcpSocket* socket) {
m_connectedClients[socket].m_port = m_httpServer.serverPort();
}
QHttpRequest* request = &m_connectedClients[socket];
HttpRequest* request = &m_connectedClients[socket];
bool error = false;
if (Q_LIKELY(request->m_state == QHttpRequest::State::ReadingMethod)) {
if (Q_LIKELY(request->m_state == HttpRequest::State::ReadingMethod)) {
if (Q_UNLIKELY(error = !request->readMethod(socket))) {
qWarningNN << LOGSEC_NETWORK << "Invalid method.";
}
}
if (Q_LIKELY(!error && request->m_state == QHttpRequest::State::ReadingUrl)) {
if (Q_LIKELY(!error && request->m_state == HttpRequest::State::ReadingUrl)) {
if (Q_UNLIKELY(error = !request->readUrl(socket))) {
qWarningNN << LOGSEC_NETWORK << "Invalid URL.";
}
}
if (Q_LIKELY(!error && request->m_state == QHttpRequest::State::ReadingStatus)) {
if (Q_LIKELY(!error && request->m_state == HttpRequest::State::ReadingStatus)) {
if (Q_UNLIKELY(error = !request->readStatus(socket))) {
qWarningNN << LOGSEC_NETWORK << "Invalid status.";
}
}
if (Q_LIKELY(!error && request->m_state == QHttpRequest::State::ReadingHeader)) {
if (Q_LIKELY(!error && request->m_state == HttpRequest::State::ReadingHeader)) {
if (Q_UNLIKELY(error = !request->readHeader(socket))) {
qWarningNN << LOGSEC_NETWORK << "Invalid header.";
}
@ -111,7 +111,7 @@ void HttpServer::readReceivedData(QTcpSocket* socket) {
m_connectedClients.remove(socket);
}
else if (!request->m_url.isEmpty()) {
Q_ASSERT(request->m_state != QHttpRequest::State::ReadingUrl);
Q_ASSERT(request->m_state != HttpRequest::State::ReadingUrl);
answerClient(socket, *request);
m_connectedClients.remove(socket);
@ -130,7 +130,7 @@ quint16 HttpServer::listenPort() const {
return m_listenPort;
}
bool HttpServer::QHttpRequest::readMethod(QTcpSocket* socket) {
bool HttpServer::HttpRequest::readMethod(QTcpSocket* socket) {
bool finished = false;
while ((socket->bytesAvailable() != 0) && !finished) {
@ -173,7 +173,7 @@ bool HttpServer::QHttpRequest::readMethod(QTcpSocket* socket) {
return true;
}
bool HttpServer::QHttpRequest::readUrl(QTcpSocket* socket) {
bool HttpServer::HttpRequest::readUrl(QTcpSocket* socket) {
bool finished = false;
while ((socket->bytesAvailable() != 0) && !finished) {
@ -208,7 +208,7 @@ bool HttpServer::QHttpRequest::readUrl(QTcpSocket* socket) {
return true;
}
bool HttpServer::QHttpRequest::readStatus(QTcpSocket* socket) {
bool HttpServer::HttpRequest::readStatus(QTcpSocket* socket) {
bool finished = false;
while ((socket->bytesAvailable() != 0) && !finished) {
@ -235,7 +235,7 @@ bool HttpServer::QHttpRequest::readStatus(QTcpSocket* socket) {
return true;
}
bool HttpServer::QHttpRequest::readHeader(QTcpSocket* socket) {
bool HttpServer::HttpRequest::readHeader(QTcpSocket* socket) {
while (socket->bytesAvailable() != 0) {
m_fragment += socket->read(1);

View File

@ -35,7 +35,7 @@ class HttpServer : public QObject {
void setListenAddressPort(const QString& full_uri, bool start_handler);
protected:
struct QHttpRequest {
struct HttpRequest {
bool readMethod(QTcpSocket* socket);
bool readUrl(QTcpSocket* socket);
bool readStatus(QTcpSocket* socket);
@ -67,7 +67,7 @@ class HttpServer : public QObject {
QMap<QByteArray, QByteArray> m_headers;
};
virtual void answerClient(QTcpSocket* socket, const QHttpRequest& request) = 0;
virtual void answerClient(QTcpSocket* socket, const HttpRequest& request) = 0;
private slots:
void clientConnected();
@ -76,7 +76,7 @@ class HttpServer : public QObject {
void readReceivedData(QTcpSocket* socket);
private:
QMap<QTcpSocket*, QHttpRequest> m_connectedClients;
QMap<QTcpSocket*, HttpRequest> m_connectedClients;
QTcpServer m_httpServer;
QHostAddress m_listenAddress;
quint16 m_listenPort;

View File

@ -44,7 +44,7 @@ void OAuthHttpHandler::handleRedirection(const QVariantMap& data) {
}
}
void OAuthHttpHandler::answerClient(QTcpSocket* socket, const QHttpRequest& request) {
void OAuthHttpHandler::answerClient(QTcpSocket* socket, const HttpRequest& request) {
if (!request.m_url.path().remove(QL1C('/')).isEmpty()) {
qCriticalNN << LOGSEC_OAUTH << "Invalid request:" << QUOTE_W_SPACE_DOT(request.m_url.toString());
}

View File

@ -17,7 +17,7 @@ class OAuthHttpHandler : public HttpServer {
void authGranted(const QString& auth_code, const QString& state);
protected:
virtual void answerClient(QTcpSocket* socket, const QHttpRequest& request);
virtual void answerClient(QTcpSocket* socket, const HttpRequest& request);
private:
void handleRedirection(const QVariantMap& data);