1
0
Fork 0
mirror of https://gitlab.com/niansa/qcommsy.git synced 2025-03-06 20:53:33 +01:00
This commit is contained in:
niansa 2020-08-11 14:22:25 +02:00
parent 22b15b2ebb
commit a48ba6c352
3 changed files with 96 additions and 42 deletions

View file

@ -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

View file

@ -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 *) {}

View file

@ -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); });
}