mirror of
https://gitlab.com/niansa/qcommsy.git
synced 2025-03-06 20:53:33 +01:00
Updated
This commit is contained in:
parent
22b15b2ebb
commit
a48ba6c352
3 changed files with 96 additions and 42 deletions
|
@ -32,13 +32,11 @@ class parsingNoSuchTagError : public std::exception {};
|
|||
class descDownloadError : public std::exception {};
|
||||
|
||||
|
||||
|
||||
static std::string server_url;
|
||||
static std::string server_sid;
|
||||
static std::string room;
|
||||
|
||||
|
||||
|
||||
std::string ltrim(const std::string& s) {
|
||||
static const std::regex lws{"^[[:space:]]*", std::regex_constants::extended};
|
||||
return std::regex_replace(s, lws, "");
|
||||
|
@ -90,6 +88,7 @@ void gumbo_search_by_attr(std::vector<GumboNode *> &elemvect, GumboNode* node, s
|
|||
if (node->type != GUMBO_NODE_ELEMENT) {
|
||||
return;
|
||||
}
|
||||
|
||||
GumboAttribute* hclass;
|
||||
if (node->v.element.tag == expectedtag &&
|
||||
(hclass = gumbo_get_attribute(&node->v.element.attributes, attrname.c_str()))) {
|
||||
|
@ -97,14 +96,17 @@ void gumbo_search_by_attr(std::vector<GumboNode *> &elemvect, GumboNode* node, s
|
|||
elemvect.push_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
GumboVector* children = &node->v.element.children;
|
||||
for (unsigned int i = 0; i < children->length; ++i) {
|
||||
gumbo_search_by_attr(elemvect, static_cast<GumboNode*>(children->data[i]), attrname, searchword, expectedtag);
|
||||
}
|
||||
}
|
||||
|
||||
void gumbo_search_by_class(std::vector<GumboNode *> &elemvect, GumboNode* node, std::string searchword, GumboTag expectedtag) {
|
||||
return gumbo_search_by_attr(elemvect, node, "class", searchword, expectedtag);
|
||||
}
|
||||
|
||||
GumboNode *gumbo_search_by_id(GumboNode* node, std::string searchword, GumboTag expectedtag) {
|
||||
std::vector<GumboNode *> elemvect;
|
||||
gumbo_search_by_attr(elemvect, node, "id", searchword, expectedtag);
|
||||
|
@ -121,9 +123,11 @@ void gumbo_search_by_tag(std::vector<GumboNode *> &elemvect, GumboNode* node, Gu
|
|||
if (node->type != GUMBO_NODE_ELEMENT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node->v.element.tag == searchedtag) {
|
||||
elemvect.push_back(node);
|
||||
}
|
||||
|
||||
GumboVector* children = &node->v.element.children;
|
||||
for (unsigned int i = 0; i < children->length; ++i) {
|
||||
gumbo_search_by_tag(elemvect, static_cast<GumboNode*>(children->data[i]), searchedtag);
|
||||
|
@ -132,22 +136,27 @@ void gumbo_search_by_tag(std::vector<GumboNode *> &elemvect, GumboNode* node, Gu
|
|||
|
||||
static std::string gumbo_cleantext(GumboNode* node) {
|
||||
if (node->type == GUMBO_NODE_TEXT) {
|
||||
return std::string(node->v.text.text);
|
||||
return std::string(node->v.text.text);
|
||||
|
||||
} else if (node->type == GUMBO_NODE_ELEMENT &&
|
||||
node->v.element.tag != GUMBO_TAG_SCRIPT &&
|
||||
node->v.element.tag != GUMBO_TAG_STYLE) {
|
||||
|
||||
std::string contents = "";
|
||||
GumboVector* children = &node->v.element.children;
|
||||
|
||||
for (unsigned int i = 0; i < children->length; ++i) {
|
||||
const std::string text = gumbo_cleantext(reinterpret_cast<GumboNode*> (children->data[i]));
|
||||
if (i != 0 && !text.empty()) {
|
||||
contents.append(" ");
|
||||
}
|
||||
contents.append(text);
|
||||
const std::string text = gumbo_cleantext(reinterpret_cast<GumboNode*> (children->data[i]));
|
||||
if (i != 0 && !text.empty()) {
|
||||
contents.append(" ");
|
||||
}
|
||||
contents.append(text);
|
||||
}
|
||||
|
||||
return contents;
|
||||
|
||||
} else {
|
||||
return "";
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,15 +165,18 @@ std::vector<std::string> gumbo_get_attr(GumboNode *node, std::string attrkey, Gu
|
|||
GumboNode *childnode;
|
||||
GumboVector* children = &node->v.element.children;
|
||||
std::vector<std::string> toappend;
|
||||
|
||||
// Check if current element is already the right one
|
||||
if (node->v.element.tag == expected_tag) {
|
||||
// Return this elements wanted attribute key
|
||||
return {gumbo_get_attribute(&node->v.element.attributes, attrkey.c_str())->value};
|
||||
}
|
||||
|
||||
// Check if This is a node element
|
||||
else if (node->type != GUMBO_NODE_ELEMENT) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Iterate through child nodes
|
||||
for (unsigned int it = 0; it < children->length; ++it) {
|
||||
childnode = reinterpret_cast<GumboNode*> (children->data[it]);
|
||||
|
@ -175,6 +187,7 @@ std::vector<std::string> gumbo_get_attr(GumboNode *node, std::string attrkey, Gu
|
|||
attrvals = merge_strvects(attrvals, toappend);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the final result
|
||||
return attrvals;
|
||||
}
|
||||
|
@ -182,6 +195,7 @@ std::vector<std::string> gumbo_get_attr(GumboNode *node, std::string attrkey, Gu
|
|||
std::string gumbo_find_text_by_tag(GumboNode *node, GumboTag searchtag) {
|
||||
GumboNode *childnode;
|
||||
GumboVector* children = &node->v.element.children;
|
||||
|
||||
// Iterate through childs
|
||||
for (unsigned int it = 0; it < children->length; ++it) {
|
||||
childnode = reinterpret_cast<GumboNode*> (children->data[it]);
|
||||
|
@ -189,6 +203,7 @@ std::string gumbo_find_text_by_tag(GumboNode *node, GumboTag searchtag) {
|
|||
return trim(gumbo_cleantext(childnode));
|
||||
}
|
||||
}
|
||||
|
||||
throw parsingNoSuchTagError();
|
||||
return "";
|
||||
}
|
||||
|
@ -228,20 +243,24 @@ std::vector<std::map<std::string, std::string>> get_post_files(GumboNode *node)
|
|||
std::vector<std::string> filenames;
|
||||
std::vector<std::map<std::string, std::string>> filenameurlmap;
|
||||
std::map<std::string, std::string> tmpmap;
|
||||
|
||||
// Get meta nodes
|
||||
gumbo_search_by_class(metanodes, node, "uk-comment-meta", GUMBO_TAG_DIV);
|
||||
// Get URLs
|
||||
fileurls = gumbo_get_attr(metanodes[2], "href", GUMBO_TAG_A);
|
||||
// Get filenames
|
||||
filenames = gumbo_get_attr(metanodes[2], "title", GUMBO_TAG_A);
|
||||
|
||||
// Generate map
|
||||
auto urlit = fileurls.begin();
|
||||
auto nameit = filenames.begin();
|
||||
while (true) {
|
||||
|
||||
// Break if last item was reached
|
||||
if (urlit == fileurls.end() or nameit == filenames.end()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Generate temporary map
|
||||
tmpmap = {};
|
||||
tmpmap[*nameit] = *urlit;
|
||||
|
@ -259,6 +278,7 @@ std::string get_post_desc(std::string post_url) {
|
|||
GumboOutput *post_document;
|
||||
GumboNode *desc_node;
|
||||
std::vector<GumboNode *> results;
|
||||
|
||||
// Get material ID
|
||||
material_id = get_filename(post_url);
|
||||
// Download post
|
||||
|
@ -267,17 +287,20 @@ std::string get_post_desc(std::string post_url) {
|
|||
if (statuscode != 200) {
|
||||
throw descDownloadError();
|
||||
}
|
||||
|
||||
// Parse post
|
||||
post_document = gumbo_parse(httpcontent.str().c_str());
|
||||
// Get description element
|
||||
desc_node = gumbo_search_by_id(post_document->root, "description" + material_id, GUMBO_TAG_DIV);
|
||||
// Extract description
|
||||
gumbo_search_by_tag(results, desc_node, GUMBO_TAG_P);
|
||||
|
||||
// Cencenate occurencies
|
||||
std::string result_string;
|
||||
for (auto it = results.begin(); it != results.end(); it++) {
|
||||
result_string.append(trim(gumbo_cleantext(*it)) + "\n");
|
||||
}
|
||||
|
||||
// Return first occurence
|
||||
return result_string;
|
||||
}
|
||||
|
@ -316,6 +339,7 @@ public:
|
|||
std::string *getDescription(unsigned long postID) {
|
||||
// Get post
|
||||
commsyPost *thispost = getPost(postID);
|
||||
|
||||
// Check if post description was downloaded already
|
||||
if (thispost->description.empty()) {
|
||||
// Download post
|
||||
|
@ -335,6 +359,7 @@ public:
|
|||
GumboOutput *document;
|
||||
long statuscode;
|
||||
numposts = 0;
|
||||
|
||||
while (1) {
|
||||
// Check connection and download feed
|
||||
try {
|
||||
|
@ -349,15 +374,18 @@ public:
|
|||
} else if (statuscode != 200) {
|
||||
throw connectionFailError();
|
||||
}
|
||||
// Do some stuff
|
||||
|
||||
// Do some stuff XD
|
||||
document = gumbo_parse(httpcontent.str().c_str());
|
||||
httpcontent.str(std::string()); // Clear buffer just in case we need it later
|
||||
|
||||
// Get posts
|
||||
auto gumboPosts = get_posts(document->root);
|
||||
if (gumboPosts.size() == 0) {
|
||||
// Stop fetching more data
|
||||
break;
|
||||
}
|
||||
|
||||
// Map posts and their corresponding URL to a number
|
||||
for (auto it = gumboPosts.begin(); it != gumboPosts.end(); it++) {
|
||||
// Create post struct
|
||||
|
@ -377,6 +405,7 @@ public:
|
|||
thispost.files.insert(filemap.begin(), filemap.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Append to posts vector
|
||||
posts.push_back(thispost);
|
||||
// Increment post counter
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include <exception>
|
||||
#include <iostream>
|
||||
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QUrlQuery>
|
||||
|
@ -13,27 +15,28 @@
|
|||
class authFailureError : public std::exception {};
|
||||
|
||||
|
||||
class libCommsyAuth : QObject {
|
||||
class libCommsyAuth : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Q_SIGNALS:
|
||||
void reEmit(QNetworkReply *r);
|
||||
|
||||
public:
|
||||
QNetworkAccessManager *mNetMan = nullptr;
|
||||
QNetworkRequest *mNetReq = nullptr;
|
||||
|
||||
libCommsyAuth() {
|
||||
explicit libCommsyAuth(QObject *p = nullptr) : QObject (p){
|
||||
mNetMan = new QNetworkAccessManager(this);
|
||||
mNetReq = new QNetworkRequest();
|
||||
connect(mNetMan, &QNetworkAccessManager::finished, this, &libCommsyAuth::reEmit);
|
||||
}
|
||||
|
||||
QNetworkAccessManager *mNetMan = nullptr;
|
||||
QNetworkRequest *mNetReq = nullptr;
|
||||
|
||||
void connectInit(const QUrl& serverBaseUrl) {
|
||||
// Initialise request
|
||||
//mNetReq->setTransferTimeout(15000);
|
||||
mNetReq->setUrl(serverBaseUrl);
|
||||
mNetReq->setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
connect(mNetMan, &QNetworkAccessManager::finished, this, &libCommsyAuth::reEmit);
|
||||
mNetMan->get(*mNetReq);
|
||||
}
|
||||
|
||||
|
@ -43,25 +46,32 @@ public:
|
|||
|
||||
void sendAuth(const QString& authUrl, const QString& username, const QString& password) {
|
||||
QUrlQuery mNetQuery;
|
||||
|
||||
// Set auth credentials
|
||||
mNetQuery.addQueryItem("user_id", username);
|
||||
mNetQuery.addQueryItem("password", password);
|
||||
|
||||
// Create request
|
||||
mNetReq->setUrl(authUrl + "&mod=context&fct=login");
|
||||
mNetReq->setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
// Perform the request return
|
||||
connect(mNetMan, &QNetworkAccessManager::finished, this, &libCommsyAuth::reEmit);
|
||||
|
||||
// Perform the request
|
||||
mNetMan->post(*mNetReq, mNetQuery.toString(QUrl::FullyEncoded).toUtf8());
|
||||
}
|
||||
|
||||
QString getSID(QNetworkReply *reply) {
|
||||
auto cookies = QNetworkCookie::parseCookies(reply->rawHeader("Set-Cookie"));
|
||||
|
||||
for (const auto& cookie : cookies) {
|
||||
if (cookie.name() == "SID") {
|
||||
std::cout << cookie.value().toStdString() << std::endl;
|
||||
return cookie.value();
|
||||
}
|
||||
}
|
||||
|
||||
throw authFailureError();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void libCommsyAuth::reEmit(QNetworkReply *) {}
|
||||
|
|
63
main.cpp
63
main.cpp
|
@ -3,6 +3,12 @@
|
|||
#include "ui_login.h"
|
||||
#include "ui_failure.h"
|
||||
#include "ui_offline.h"
|
||||
|
||||
#include "libcommsy.hpp"
|
||||
#include "libcommsyauth.hpp"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QApplication>
|
||||
#include <QPushButton>
|
||||
|
@ -13,10 +19,6 @@
|
|||
#include <QNetworkReply>
|
||||
#include <QDesktopServices>
|
||||
#include <QSettings>
|
||||
#include <limits.h>
|
||||
|
||||
#include "libcommsy.hpp"
|
||||
#include "libcommsyauth.hpp"
|
||||
|
||||
#define QCommsy_NAME "QCommsy"
|
||||
#define QCommsy_VERSION "0.1-alpha"
|
||||
|
@ -61,15 +63,18 @@ public:
|
|||
|
||||
void _UILoader::infoWindow(QMainWindow *w) {
|
||||
Ui::infoWindow *thisui = new Ui::infoWindow;
|
||||
|
||||
// Show initial UI
|
||||
thisui->setupUi(w);
|
||||
w->show();
|
||||
|
||||
// Update version info
|
||||
thisui->versionInfo->setText(
|
||||
"<b>App frontend:</b> " QCommsy_NAME " version " QCommsy_VERSION "<br />"
|
||||
"<b>Authentication backend:</b> " libCommsyAuth_NAME " version " libCommsyAuth_VERSION "<br />"
|
||||
"<b>Scrapping backend:</b> " libCommsy_NAME " version " libCommsy_VERSION
|
||||
);
|
||||
|
||||
// Add button handlers
|
||||
w->connect(thisui->backButton, &QPushButton::pressed, [this, w] () {
|
||||
loginWindow(w);
|
||||
|
@ -79,68 +84,74 @@ void _UILoader::infoWindow(QMainWindow *w) {
|
|||
void _UILoader::failureWindow(QMainWindow *w) {
|
||||
Ui::failureWindow *thisui = new Ui::failureWindow;
|
||||
QString reason;
|
||||
|
||||
// Show initial UI
|
||||
thisui->setupUi(w);
|
||||
w->show();
|
||||
|
||||
// Get error message
|
||||
reason = "Ein interner Fehler ist aufgetreten<br />"
|
||||
"<i>Dies ist sehr wahrscheinlich ein Programmfehler. Sollte das zu häufig passieren, kontaktiere bitte den Entwickler</i>";
|
||||
|
||||
// Show error message
|
||||
thisui->descriptionText->setText("<b>Verbindung fehlgeschlagen</b><br />" + reason);
|
||||
|
||||
// Add button handlers
|
||||
w->connect(thisui->retryButton, &QPushButton::pressed, [this, w] () {
|
||||
loginWindow(w);
|
||||
});
|
||||
w->connect(thisui->logoutButton, &QPushButton::pressed, [this, w] () {
|
||||
logout();
|
||||
loginWindow(w);
|
||||
});
|
||||
w->connect(thisui->retryButton, &QPushButton::pressed, [this, w] () { loginWindow(w); });
|
||||
w->connect(thisui->logoutButton, &QPushButton::pressed, [this, w] () { logout(); loginWindow(w); });
|
||||
}
|
||||
|
||||
void _UILoader::offlineWindow(QMainWindow *w) {
|
||||
Ui::offlineWindow *thisui = new Ui::offlineWindow;
|
||||
QString reason;
|
||||
|
||||
// Show initial UI
|
||||
thisui->setupUi(w);
|
||||
w->show();
|
||||
// Add button handlers
|
||||
w->connect(thisui->logoutButton, &QPushButton::pressed, [this, w] () {
|
||||
logout();
|
||||
loginWindow(w);
|
||||
});
|
||||
w->connect(thisui->logoutButton, &QPushButton::pressed, [this, w] () { logout(); loginWindow(w); });
|
||||
}
|
||||
|
||||
void _UILoader::loginWindow(QMainWindow *w, const QString& failure) {
|
||||
Ui::loginWindow *thisui = new Ui::loginWindow;
|
||||
|
||||
// Check if logged in already
|
||||
if (settings->contains("server_sid")) {
|
||||
return overviewWindow(w);
|
||||
}
|
||||
|
||||
// Show initial UI
|
||||
thisui->setupUi(w);
|
||||
w->show();
|
||||
|
||||
// Restore login data if wanted
|
||||
bool restoreForm = settings->value("server_save", false).toBool();
|
||||
if (restoreForm) {
|
||||
thisui->saveBox->setCheckState(Qt::Checked);
|
||||
//... TODO
|
||||
}
|
||||
|
||||
// Set failure text
|
||||
thisui->failureText->setText(failure);
|
||||
|
||||
// Add button handlers
|
||||
w->connect(thisui->loginButton, &QPushButton::pressed, [this, thisui, w] () {
|
||||
// Check input lines
|
||||
if (thisui->adressLine->text().isEmpty() or thisui->usernameLine->text().isEmpty() or thisui->roomLine->text().isEmpty() or thisui->passwordLine->text().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Save basic server credentials
|
||||
settings->setValue("server_save", thisui->saveBox->checkState() == Qt::Checked);
|
||||
settings->setValue("server_url", thisui->adressLine->text());
|
||||
settings->setValue("server_room", thisui->roomLine->text());
|
||||
|
||||
// Connect
|
||||
w->connect(libCommsyAuth, &libCommsyAuth::reEmit, [this, thisui, w] (QNetworkReply *netReply) {
|
||||
w->connect(auther, &libCommsyAuth::reEmit, [this, thisui, w] (QNetworkReply *netReply) {
|
||||
std::cout << auther->getAuthUrl(netReply).toStdString() << std::endl;
|
||||
// Get SID
|
||||
w->connect(libCommsyAuth, &libCommsyAuth::reEmit, [this, thisui, w] (QNetworkReply *netReply) {
|
||||
|
||||
w->connect(auther, &libCommsyAuth::reEmit, [this, thisui, w] (QNetworkReply *netReply) {
|
||||
// Login
|
||||
try {
|
||||
settings->setValue("server_sid", auther->getSID(netReply));
|
||||
|
@ -152,14 +163,17 @@ void _UILoader::loginWindow(QMainWindow *w, const QString& failure) {
|
|||
thisui->failureText->setText("Der angegebene Raum existiert nicht");
|
||||
}
|
||||
});
|
||||
|
||||
auther->sendAuth(auther->getAuthUrl(netReply), thisui->usernameLine->text(), thisui->passwordLine->text());
|
||||
});
|
||||
|
||||
auther->connectInit(thisui->adressLine->text());
|
||||
});
|
||||
}
|
||||
|
||||
void _UILoader::overviewWindow(QMainWindow *w, bool catchInvalidRoomError) {
|
||||
Ui::overviewWindow *thisui = new Ui::overviewWindow;
|
||||
|
||||
// Connect if required
|
||||
try {
|
||||
reconnect();
|
||||
|
@ -167,37 +181,38 @@ void _UILoader::overviewWindow(QMainWindow *w, bool catchInvalidRoomError) {
|
|||
logout();
|
||||
return loginWindow(w, "Die Sitzung ist abgelaufen - bitte erneut anmelden");
|
||||
} catch (invalidRoomError& exception) {
|
||||
|
||||
if (catchInvalidRoomError) {
|
||||
logout();
|
||||
return loginWindow(w, "Der Raum existiert nicht mehr");
|
||||
} else {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
} catch (connectionFailError&) {
|
||||
return offlineWindow(w);
|
||||
} catch (std::exception&) {
|
||||
return failureWindow(w);
|
||||
}
|
||||
|
||||
// Show initial UI
|
||||
thisui->setupUi(w);
|
||||
w->show();
|
||||
|
||||
// Refresh view
|
||||
thisui->postCounter->setText(QString::number(connector->numposts) + " Einträge");
|
||||
thisui->postList->clear();
|
||||
for (const auto& thispost : connector->posts) {
|
||||
thisui->postList->addItem(QString::fromStdString(thispost.name));
|
||||
}
|
||||
|
||||
// Add button handlers
|
||||
w->connect(thisui->postList, &QListWidget::activated, [this, thisui] (QModelIndex index) {
|
||||
QDesktopServices::openUrl(QUrl(settings->value("server_url").toString() + QString::fromStdString(connector->getPost(index.row())->url)));
|
||||
});
|
||||
w->connect(thisui->logoutButton, &QPushButton::pressed, [this, w] () {
|
||||
logout();
|
||||
loginWindow(w);
|
||||
});
|
||||
w->connect(thisui->infoButton, &QPushButton::pressed, [this, w] () {
|
||||
infoWindow(w);
|
||||
});
|
||||
|
||||
w->connect(thisui->logoutButton, &QPushButton::pressed, [this, w] () { logout(); loginWindow(w); });
|
||||
w->connect(thisui->infoButton, &QPushButton::pressed, [this, w] () { infoWindow(w); });
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue