api work
This commit is contained in:
parent
aa7b18827c
commit
6b9041a110
@ -1 +1 @@
|
|||||||
Subproject commit 2b41d67a372b6ce42ed666e7d88e7815694f1966
|
Subproject commit b874b2fad4fcb91861b62ae2a52df44efac98ddd
|
@ -275,10 +275,6 @@ QList<Feed*> FeedsModel::feedsForScheduledUpdate(bool auto_update_now) {
|
|||||||
return feeds_for_update;
|
return feeds_for_update;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Message> FeedsModel::messagesForItem(RootItem* item) const {
|
|
||||||
return item->undeletedMessages();
|
|
||||||
}
|
|
||||||
|
|
||||||
int FeedsModel::columnCount(const QModelIndex& parent) const {
|
int FeedsModel::columnCount(const QModelIndex& parent) const {
|
||||||
Q_UNUSED(parent)
|
Q_UNUSED(parent)
|
||||||
return FEEDS_VIEW_COLUMN_COUNT;
|
return FEEDS_VIEW_COLUMN_COUNT;
|
||||||
|
@ -54,11 +54,6 @@ class RSSGUARD_DLLSPEC FeedsModel : public QAbstractItemModel {
|
|||||||
// This method might change some properties of some feeds.
|
// This method might change some properties of some feeds.
|
||||||
QList<Feed*> feedsForScheduledUpdate(bool auto_update_now);
|
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.
|
// Returns ALL RECURSIVE CHILD feeds contained within single index.
|
||||||
QList<Feed*> feedsForIndex(const QModelIndex& index = QModelIndex()) const;
|
QList<Feed*> feedsForIndex(const QModelIndex& index = QModelIndex()) const;
|
||||||
|
|
||||||
|
@ -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) {
|
Message Message::fromSqlRecord(const QSqlRecord& record, bool* result) {
|
||||||
if (record.count() != MSG_DB_LABELS_IDS + 1) {
|
if (record.count() != MSG_DB_LABELS_IDS + 1) {
|
||||||
if (result != nullptr) {
|
if (result != nullptr) {
|
||||||
|
@ -56,6 +56,8 @@ class RSSGUARD_DLLSPEC Message {
|
|||||||
|
|
||||||
void sanitize(const Feed* feed, bool fix_future_datetimes);
|
void sanitize(const Feed* feed, bool fix_future_datetimes);
|
||||||
|
|
||||||
|
QJsonObject toJson() const;
|
||||||
|
|
||||||
// Creates Message from given record, which contains
|
// Creates Message from given record, which contains
|
||||||
// row from query SELECT * FROM Messages WHERE ....;
|
// row from query SELECT * FROM Messages WHERE ....;
|
||||||
static Message fromSqlRecord(const QSqlRecord& record, bool* result = nullptr);
|
static Message fromSqlRecord(const QSqlRecord& record, bool* result = nullptr);
|
||||||
|
@ -1174,6 +1174,55 @@ QList<Message> DatabaseQueries::getUndeletedUnreadMessages(const QSqlDatabase& d
|
|||||||
return messages;
|
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,
|
QList<Message> DatabaseQueries::getUndeletedMessagesForFeed(const QSqlDatabase& db,
|
||||||
const QString& feed_custom_id,
|
const QString& feed_custom_id,
|
||||||
int account_id,
|
int account_id,
|
||||||
|
@ -118,6 +118,14 @@ class DatabaseQueries {
|
|||||||
static QList<Message> getUndeletedMessagesForBin(const QSqlDatabase& db, int account_id, bool* ok = nullptr);
|
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> 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.
|
// Custom ID accumulators.
|
||||||
static QStringList bagOfMessages(const QSqlDatabase& db, ServiceRoot::BagOfMessages bag, const Feed* feed);
|
static QStringList bagOfMessages(const QSqlDatabase& db, ServiceRoot::BagOfMessages bag, const Feed* feed);
|
||||||
static QHash<QString, QStringList> bagsOfMessages(const QSqlDatabase& db, const QList<Label*>& labels);
|
static QHash<QString, QStringList> bagsOfMessages(const QSqlDatabase& db, const QList<Label*>& labels);
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
ApiServer::ApiServer(QObject* parent) : HttpServer(parent) {}
|
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 incoming_data = socket->readAll();
|
||||||
QByteArray output_data;
|
QByteArray output_data;
|
||||||
|
|
||||||
@ -26,10 +26,18 @@ void ApiServer::answerClient(QTcpSocket* socket, const QHttpRequest& request) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ApiRequest req(incoming_doc);
|
ApiRequest req(incoming_doc);
|
||||||
|
|
||||||
|
try {
|
||||||
ApiResponse resp(processRequest(req));
|
ApiResponse resp(processRequest(req));
|
||||||
|
|
||||||
output_data = resp.toJson().toJson();
|
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"
|
const QByteArray reply_message = QSL("HTTP/1.0 200 OK \r\n"
|
||||||
"Content-Type: application/json; charset=\"utf-8\"\r\n"
|
"Content-Type: application/json; charset=\"utf-8\"\r\n"
|
||||||
@ -63,17 +71,23 @@ ApiResponse ApiServer::processAppVersion() const {
|
|||||||
|
|
||||||
ApiResponse ApiServer::processArticlesFromFeed(const QJsonValue& req) const {
|
ApiResponse ApiServer::processArticlesFromFeed(const QJsonValue& req) const {
|
||||||
QJsonObject data = req.toObject();
|
QJsonObject data = req.toObject();
|
||||||
|
|
||||||
QString feed_id = data.value(QSL("feed")).toString();
|
QString feed_id = data.value(QSL("feed")).toString();
|
||||||
int account_id = data.value(QSL("account")).toInt();
|
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());
|
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;
|
QJsonArray msgs_json_array;
|
||||||
|
|
||||||
for (const Message& msg : msgs) {
|
for (const Message& msg : msgs) {
|
||||||
QJsonObject msg_obj;
|
QJsonObject msg_obj;
|
||||||
|
|
||||||
msg_obj.insert(QSL("contents"), msg.m_contents);
|
msg_obj.insert(QSL("contents"), msg.toJson());
|
||||||
msgs_json_array.append(msg_obj);
|
msgs_json_array.append(msg_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ class ApiServer : public HttpServer {
|
|||||||
explicit ApiServer(QObject* parent = nullptr);
|
explicit ApiServer(QObject* parent = nullptr);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void answerClient(QTcpSocket* socket, const QHttpRequest& request);
|
virtual void answerClient(QTcpSocket* socket, const HttpRequest& request);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ApiResponse processRequest(const ApiRequest& req) const;
|
ApiResponse processRequest(const ApiRequest& req) const;
|
||||||
|
@ -79,28 +79,28 @@ void HttpServer::readReceivedData(QTcpSocket* socket) {
|
|||||||
m_connectedClients[socket].m_port = m_httpServer.serverPort();
|
m_connectedClients[socket].m_port = m_httpServer.serverPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
QHttpRequest* request = &m_connectedClients[socket];
|
HttpRequest* request = &m_connectedClients[socket];
|
||||||
bool error = false;
|
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))) {
|
if (Q_UNLIKELY(error = !request->readMethod(socket))) {
|
||||||
qWarningNN << LOGSEC_NETWORK << "Invalid method.";
|
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))) {
|
if (Q_UNLIKELY(error = !request->readUrl(socket))) {
|
||||||
qWarningNN << LOGSEC_NETWORK << "Invalid URL.";
|
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))) {
|
if (Q_UNLIKELY(error = !request->readStatus(socket))) {
|
||||||
qWarningNN << LOGSEC_NETWORK << "Invalid status.";
|
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))) {
|
if (Q_UNLIKELY(error = !request->readHeader(socket))) {
|
||||||
qWarningNN << LOGSEC_NETWORK << "Invalid header.";
|
qWarningNN << LOGSEC_NETWORK << "Invalid header.";
|
||||||
}
|
}
|
||||||
@ -111,7 +111,7 @@ void HttpServer::readReceivedData(QTcpSocket* socket) {
|
|||||||
m_connectedClients.remove(socket);
|
m_connectedClients.remove(socket);
|
||||||
}
|
}
|
||||||
else if (!request->m_url.isEmpty()) {
|
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);
|
answerClient(socket, *request);
|
||||||
m_connectedClients.remove(socket);
|
m_connectedClients.remove(socket);
|
||||||
@ -130,7 +130,7 @@ quint16 HttpServer::listenPort() const {
|
|||||||
return m_listenPort;
|
return m_listenPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HttpServer::QHttpRequest::readMethod(QTcpSocket* socket) {
|
bool HttpServer::HttpRequest::readMethod(QTcpSocket* socket) {
|
||||||
bool finished = false;
|
bool finished = false;
|
||||||
|
|
||||||
while ((socket->bytesAvailable() != 0) && !finished) {
|
while ((socket->bytesAvailable() != 0) && !finished) {
|
||||||
@ -173,7 +173,7 @@ bool HttpServer::QHttpRequest::readMethod(QTcpSocket* socket) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HttpServer::QHttpRequest::readUrl(QTcpSocket* socket) {
|
bool HttpServer::HttpRequest::readUrl(QTcpSocket* socket) {
|
||||||
bool finished = false;
|
bool finished = false;
|
||||||
|
|
||||||
while ((socket->bytesAvailable() != 0) && !finished) {
|
while ((socket->bytesAvailable() != 0) && !finished) {
|
||||||
@ -208,7 +208,7 @@ bool HttpServer::QHttpRequest::readUrl(QTcpSocket* socket) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HttpServer::QHttpRequest::readStatus(QTcpSocket* socket) {
|
bool HttpServer::HttpRequest::readStatus(QTcpSocket* socket) {
|
||||||
bool finished = false;
|
bool finished = false;
|
||||||
|
|
||||||
while ((socket->bytesAvailable() != 0) && !finished) {
|
while ((socket->bytesAvailable() != 0) && !finished) {
|
||||||
@ -235,7 +235,7 @@ bool HttpServer::QHttpRequest::readStatus(QTcpSocket* socket) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HttpServer::QHttpRequest::readHeader(QTcpSocket* socket) {
|
bool HttpServer::HttpRequest::readHeader(QTcpSocket* socket) {
|
||||||
while (socket->bytesAvailable() != 0) {
|
while (socket->bytesAvailable() != 0) {
|
||||||
m_fragment += socket->read(1);
|
m_fragment += socket->read(1);
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ class HttpServer : public QObject {
|
|||||||
void setListenAddressPort(const QString& full_uri, bool start_handler);
|
void setListenAddressPort(const QString& full_uri, bool start_handler);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct QHttpRequest {
|
struct HttpRequest {
|
||||||
bool readMethod(QTcpSocket* socket);
|
bool readMethod(QTcpSocket* socket);
|
||||||
bool readUrl(QTcpSocket* socket);
|
bool readUrl(QTcpSocket* socket);
|
||||||
bool readStatus(QTcpSocket* socket);
|
bool readStatus(QTcpSocket* socket);
|
||||||
@ -67,7 +67,7 @@ class HttpServer : public QObject {
|
|||||||
QMap<QByteArray, QByteArray> m_headers;
|
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:
|
private slots:
|
||||||
void clientConnected();
|
void clientConnected();
|
||||||
@ -76,7 +76,7 @@ class HttpServer : public QObject {
|
|||||||
void readReceivedData(QTcpSocket* socket);
|
void readReceivedData(QTcpSocket* socket);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMap<QTcpSocket*, QHttpRequest> m_connectedClients;
|
QMap<QTcpSocket*, HttpRequest> m_connectedClients;
|
||||||
QTcpServer m_httpServer;
|
QTcpServer m_httpServer;
|
||||||
QHostAddress m_listenAddress;
|
QHostAddress m_listenAddress;
|
||||||
quint16 m_listenPort;
|
quint16 m_listenPort;
|
||||||
|
@ -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()) {
|
if (!request.m_url.path().remove(QL1C('/')).isEmpty()) {
|
||||||
qCriticalNN << LOGSEC_OAUTH << "Invalid request:" << QUOTE_W_SPACE_DOT(request.m_url.toString());
|
qCriticalNN << LOGSEC_OAUTH << "Invalid request:" << QUOTE_W_SPACE_DOT(request.m_url.toString());
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ class OAuthHttpHandler : public HttpServer {
|
|||||||
void authGranted(const QString& auth_code, const QString& state);
|
void authGranted(const QString& auth_code, const QString& state);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void answerClient(QTcpSocket* socket, const QHttpRequest& request);
|
virtual void answerClient(QTcpSocket* socket, const HttpRequest& request);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handleRedirection(const QVariantMap& data);
|
void handleRedirection(const QVariantMap& data);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user