mirror of
https://gitlab.com/niansa/qcommsy.git
synced 2025-03-06 20:53:33 +01:00
Moved libcommsy into own object (critical bug known)
This commit is contained in:
parent
7877bcbbe2
commit
7393917d50
5 changed files with 504 additions and 488 deletions
|
@ -16,6 +16,7 @@ DEFINES += QT_DEPRECATED_WARNINGS
|
||||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
libcommsy.cpp \
|
||||||
main.cpp
|
main.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
|
|
440
libcommsy.cpp
Normal file
440
libcommsy.cpp
Normal file
|
@ -0,0 +1,440 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <regex>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
#include <csignal>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <curlpp/cURLpp.hpp>
|
||||||
|
#include <curlpp/Easy.hpp>
|
||||||
|
#include <curlpp/Infos.hpp>
|
||||||
|
#include <curlpp/Options.hpp>
|
||||||
|
|
||||||
|
#include <gumbo.h>
|
||||||
|
|
||||||
|
#include "libcommsy.hpp"
|
||||||
|
|
||||||
|
class parsingNoSuchIDError {};
|
||||||
|
class parsingNoSuchTagError {};
|
||||||
|
class descDownloadError {};
|
||||||
|
|
||||||
|
|
||||||
|
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, "");
|
||||||
|
}
|
||||||
|
std::string rtrim(const std::string& s) {
|
||||||
|
static const std::regex tws{"[[:space:]]*$", std::regex_constants::extended};
|
||||||
|
return std::regex_replace(s, tws, "");
|
||||||
|
}
|
||||||
|
std::string trim(const std::string& s) {
|
||||||
|
return ltrim(rtrim(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_filename(const std::string& path) {
|
||||||
|
return path.substr(path.find_last_of("/\\") + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string clean_spaces(const std::string& s) {
|
||||||
|
static const std::regex tws{"[ ]{2,}", std::regex_constants::extended};
|
||||||
|
std::string newstr = std::regex_replace(s, tws, "");
|
||||||
|
std::replace(newstr.begin(), newstr.end(), '\n', ' ');
|
||||||
|
newstr.erase(0, 4);
|
||||||
|
return newstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> merge_strvects(std::vector<std::string> base, const std::vector<std::string> &addition) {
|
||||||
|
base.insert(base.end(), addition.begin(), addition.end());
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long curlreq(std::stringstream &responsebuffer, std::string SID, std::string URL) {
|
||||||
|
std::cout << "Connection details begin" << std::endl;
|
||||||
|
std::cout << "URL: " << URL << std::endl;
|
||||||
|
std::cout << "SID: " << SID << std::endl;
|
||||||
|
std::cout << "Connection details end" << std::endl;
|
||||||
|
// Initialise variables
|
||||||
|
curlpp::Cleanup cleaner;
|
||||||
|
curlpp::Easy request;
|
||||||
|
// Set the writer callback to enable cURL to write result in a memory area
|
||||||
|
request.setOpt(new curlpp::options::WriteStream(&responsebuffer));
|
||||||
|
// Setting the URL to retrive.
|
||||||
|
request.setOpt(new curlpp::options::Url(URL));
|
||||||
|
// Set SID cookie
|
||||||
|
std::list<std::string> header;
|
||||||
|
header.push_back("Cookie: SID=" + SID);
|
||||||
|
request.setOpt(new curlpp::options::HttpHeader(header));
|
||||||
|
// Perform request
|
||||||
|
request.perform();
|
||||||
|
// Return result
|
||||||
|
return curlpp::infos::ResponseCode::get(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gumbo_search_by_attr(std::vector<GumboNode *> &elemvect, GumboNode* node, std::string attrname, std::string searchword, GumboTag expectedtag) {
|
||||||
|
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()))) {
|
||||||
|
if (hclass->value == searchword) {
|
||||||
|
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);
|
||||||
|
// Use first node found
|
||||||
|
if (elemvect.size() > 0) {
|
||||||
|
return elemvect[0];
|
||||||
|
}
|
||||||
|
// If no nodes were found, panic()
|
||||||
|
throw parsingNoSuchIDError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void gumbo_search_by_tag(std::vector<GumboNode *> &elemvect, GumboNode* node, GumboTag searchedtag) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string gumbo_cleantext(GumboNode* node) {
|
||||||
|
if (node->type == GUMBO_NODE_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return contents;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> gumbo_get_attr(GumboNode *node, std::string attrkey, GumboTag expected_tag) {
|
||||||
|
std::vector<std::string> attrvals;
|
||||||
|
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]);
|
||||||
|
if (childnode->v.element.tag == expected_tag) { // If node is the expected tag; use it
|
||||||
|
attrvals.push_back(gumbo_get_attribute(&childnode->v.element.attributes, attrkey.c_str())->value);
|
||||||
|
} else if (childnode->type == GUMBO_NODE_ELEMENT) { // Else; iterate through its child nodes
|
||||||
|
toappend = gumbo_get_attr(childnode, attrkey, expected_tag);
|
||||||
|
attrvals = merge_strvects(attrvals, toappend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the final result
|
||||||
|
return attrvals;
|
||||||
|
}
|
||||||
|
|
||||||
|
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]);
|
||||||
|
if (childnode->v.element.tag == searchtag) { // If node is the expected tag; check content
|
||||||
|
return trim(gumbo_cleantext(childnode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw parsingNoSuchTagError();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto get_posts(GumboNode *node) {
|
||||||
|
std::vector<GumboNode *> posts;
|
||||||
|
gumbo_search_by_class(posts, node, "uk-comment", GUMBO_TAG_ARTICLE);
|
||||||
|
return posts;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_post_name(GumboNode *node) {
|
||||||
|
std::vector<GumboNode *> titlenodes;
|
||||||
|
gumbo_search_by_class(titlenodes, node, "uk-comment-title", GUMBO_TAG_H4);
|
||||||
|
return trim(gumbo_cleantext(titlenodes[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_post_id(GumboNode *node) {
|
||||||
|
return gumbo_get_attr(node, "data-item-id", GUMBO_TAG_ARTICLE)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_post_meta(GumboNode *node) {
|
||||||
|
std::vector<GumboNode *> metanodes;
|
||||||
|
gumbo_search_by_class(metanodes, node, "uk-comment-meta", GUMBO_TAG_DIV);
|
||||||
|
return clean_spaces(trim(gumbo_cleantext(metanodes[1])));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_post_url(GumboNode *node) {
|
||||||
|
std::vector<GumboNode *> titlenodes;
|
||||||
|
gumbo_search_by_class(titlenodes, node, "uk-comment-title", GUMBO_TAG_H4);
|
||||||
|
return gumbo_get_attr(titlenodes[0], "href", GUMBO_TAG_A)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_post_unread(GumboNode *node) {
|
||||||
|
std::vector<GumboNode *> elems;
|
||||||
|
gumbo_search_by_class(elems, node, "cs-comment-change-info", GUMBO_TAG_DIV);
|
||||||
|
return !elems.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
taskState::type get_post_taskState(GumboNode *node) {
|
||||||
|
// Find all elements that could contain the information we need and grab their "class" attribute
|
||||||
|
std::vector<std::string> divClassAttrs;
|
||||||
|
divClassAttrs = gumbo_get_attr(node, "class", GUMBO_TAG_I);
|
||||||
|
|
||||||
|
// Try to find the information we need
|
||||||
|
for (const auto& classAttr : divClassAttrs) {
|
||||||
|
if (classAttr.find("todo") != std::string::npos) {
|
||||||
|
return taskState::todo;
|
||||||
|
} else if (classAttr.find("inProgress") != std::string::npos) {
|
||||||
|
return taskState::inProgress;
|
||||||
|
} else if (classAttr.find("done") != std::string::npos) {
|
||||||
|
return taskState::done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return taskState::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::map<std::string, std::string>> get_post_files(GumboNode *node) {
|
||||||
|
std::vector<GumboNode *> metanodes;
|
||||||
|
std::vector<std::string> fileurls;
|
||||||
|
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;
|
||||||
|
// Append it to the result vector map
|
||||||
|
filenameurlmap.push_back(tmpmap);
|
||||||
|
// Get next item in both vectors
|
||||||
|
urlit++; nameit++;
|
||||||
|
}
|
||||||
|
return filenameurlmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_post_desc(std::string post_url) {
|
||||||
|
std::string material_id;
|
||||||
|
std::stringstream httpcontent;
|
||||||
|
GumboOutput *post_document;
|
||||||
|
GumboNode *desc_node;
|
||||||
|
std::vector<GumboNode *> results;
|
||||||
|
|
||||||
|
// Get material ID
|
||||||
|
material_id = get_filename(post_url);
|
||||||
|
// Download post
|
||||||
|
long statuscode = curlreq(httpcontent, server_sid, post_url);
|
||||||
|
// Check statuscode
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
bool libCommsy::postExists(unsigned long postID) {
|
||||||
|
return postID < numposts;
|
||||||
|
}
|
||||||
|
|
||||||
|
commsyPost *libCommsy::getPost(unsigned long postID) {
|
||||||
|
// Check if post exists
|
||||||
|
if (not postExists(postID)) {
|
||||||
|
throw invalidPostError();
|
||||||
|
}
|
||||||
|
// Return post pointer
|
||||||
|
return &posts[postID];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string *libCommsy::getDescription(unsigned long postID) {
|
||||||
|
// Get post
|
||||||
|
commsyPost *thispost = getPost(postID);
|
||||||
|
|
||||||
|
// Check if post description was downloaded already
|
||||||
|
if (thispost->description == "\xFF") {
|
||||||
|
// Download post
|
||||||
|
thispost->description = get_post_desc(server_url + thispost->url);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return it
|
||||||
|
return &thispost->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
libCommsy::libCommsy(const std::string& _server_url, const std::string& _server_sid, const std::string& _room, const std::string start_id, const unsigned long max_posts) {
|
||||||
|
// Define required variables
|
||||||
|
server_url = _server_url;
|
||||||
|
server_sid = _server_sid;
|
||||||
|
room = _room;
|
||||||
|
lastID = start_id;
|
||||||
|
std::stringstream httpcontent;
|
||||||
|
GumboOutput *document;
|
||||||
|
long statuscode;
|
||||||
|
numposts = 0;
|
||||||
|
|
||||||
|
// Loop until all or max_posts posts are fetched
|
||||||
|
while (1) {
|
||||||
|
// Check connection and download feed
|
||||||
|
try {
|
||||||
|
statuscode = curlreq(httpcontent, server_sid, server_url + "/room/" + room + "/feed/10/date?lastId=" + lastID);
|
||||||
|
} catch (std::exception&) {
|
||||||
|
throw connectionFailError();
|
||||||
|
}
|
||||||
|
if (statuscode == 302) {
|
||||||
|
throw invalidSIDError();
|
||||||
|
} else if (statuscode == 500) {
|
||||||
|
throw invalidRoomError();
|
||||||
|
} else if (statuscode != 200) {
|
||||||
|
std::cout << "Unhandled status code " << statuscode << std::endl;
|
||||||
|
throw connectionFailError();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
commsyPost thispost;
|
||||||
|
{
|
||||||
|
// Get posts name
|
||||||
|
thispost.name = get_post_name(*it);
|
||||||
|
// Get posts ID
|
||||||
|
thispost.id = get_post_id(*it);
|
||||||
|
// Get posts meta string
|
||||||
|
thispost.meta = get_post_meta(*it);
|
||||||
|
// Get if post is unread
|
||||||
|
thispost.unread = get_post_unread(*it);
|
||||||
|
// Get posts task state
|
||||||
|
thispost.taskState = get_post_taskState(*it);
|
||||||
|
// Get posts URL
|
||||||
|
thispost.url = get_post_url(*it);
|
||||||
|
// Get posts files
|
||||||
|
auto files = get_post_files(*it);
|
||||||
|
for (const auto& filemap : files) {
|
||||||
|
for (const auto& [filename, fileurl] : filemap) {
|
||||||
|
commsyFile thisfile;
|
||||||
|
{
|
||||||
|
thisfile.name = filename;
|
||||||
|
thisfile.url = fileurl;
|
||||||
|
}
|
||||||
|
thispost.files.push_back(thisfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append to posts vector
|
||||||
|
posts.push_back(thispost);
|
||||||
|
// Increment post counter
|
||||||
|
numposts++;
|
||||||
|
// Get lastID
|
||||||
|
lastID = posts.back().id;
|
||||||
|
// Check if maximum amount of posts to load was exceeded
|
||||||
|
if (numposts == max_posts) {
|
||||||
|
// Stop loading more posts
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
442
libcommsy.hpp
442
libcommsy.hpp
|
@ -1,337 +1,13 @@
|
||||||
#include <iostream>
|
#include <string>
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
|
||||||
#include <regex>
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
|
||||||
#include <csignal>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <curlpp/cURLpp.hpp>
|
|
||||||
#include <curlpp/Easy.hpp>
|
|
||||||
#include <curlpp/Infos.hpp>
|
|
||||||
#include <curlpp/Options.hpp>
|
|
||||||
|
|
||||||
#include <gumbo.h>
|
|
||||||
|
|
||||||
class invalidSIDError {};
|
|
||||||
class invalidRoomError {};
|
|
||||||
class invalidPostError {};
|
|
||||||
class connectionFailError {};
|
|
||||||
class parsingNoSuchIDError {};
|
|
||||||
class parsingNoSuchTagError {};
|
|
||||||
class descDownloadError {};
|
|
||||||
|
|
||||||
|
|
||||||
static std::string server_url;
|
|
||||||
static std::string server_sid;
|
|
||||||
static std::string room;
|
|
||||||
|
|
||||||
namespace taskState {
|
namespace taskState {
|
||||||
enum type {none, done, inProgress, todo};
|
enum type {none, done, inProgress, todo};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string ltrim(const std::string& s) {
|
|
||||||
static const std::regex lws{"^[[:space:]]*", std::regex_constants::extended};
|
|
||||||
return std::regex_replace(s, lws, "");
|
|
||||||
}
|
|
||||||
std::string rtrim(const std::string& s) {
|
|
||||||
static const std::regex tws{"[[:space:]]*$", std::regex_constants::extended};
|
|
||||||
return std::regex_replace(s, tws, "");
|
|
||||||
}
|
|
||||||
std::string trim(const std::string& s) {
|
|
||||||
return ltrim(rtrim(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string get_filename(const std::string& path) {
|
|
||||||
return path.substr(path.find_last_of("/\\") + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string clean_spaces(const std::string& s) {
|
|
||||||
static const std::regex tws{"[ ]{2,}", std::regex_constants::extended};
|
|
||||||
std::string newstr = std::regex_replace(s, tws, "");
|
|
||||||
std::replace(newstr.begin(), newstr.end(), '\n', ' ');
|
|
||||||
newstr.erase(0, 4);
|
|
||||||
return newstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> merge_strvects(std::vector<std::string> base, const std::vector<std::string> &addition) {
|
|
||||||
base.insert(base.end(), addition.begin(), addition.end());
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long curlreq(std::stringstream &responsebuffer, std::string SID, std::string URL) {
|
|
||||||
std::cout << "Connection details begin" << std::endl;
|
|
||||||
std::cout << "URL: " << URL << std::endl;
|
|
||||||
std::cout << "SID: " << SID << std::endl;
|
|
||||||
std::cout << "Connection details end" << std::endl;
|
|
||||||
// Initialise variables
|
|
||||||
curlpp::Cleanup cleaner;
|
|
||||||
curlpp::Easy request;
|
|
||||||
// Set the writer callback to enable cURL to write result in a memory area
|
|
||||||
request.setOpt(new curlpp::options::WriteStream(&responsebuffer));
|
|
||||||
// Setting the URL to retrive.
|
|
||||||
request.setOpt(new curlpp::options::Url(URL));
|
|
||||||
// Set SID cookie
|
|
||||||
std::list<std::string> header;
|
|
||||||
header.push_back("Cookie: SID=" + SID);
|
|
||||||
request.setOpt(new curlpp::options::HttpHeader(header));
|
|
||||||
// Perform request
|
|
||||||
request.perform();
|
|
||||||
// Return result
|
|
||||||
return curlpp::infos::ResponseCode::get(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
void gumbo_search_by_attr(std::vector<GumboNode *> &elemvect, GumboNode* node, std::string attrname, std::string searchword, GumboTag expectedtag) {
|
|
||||||
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()))) {
|
|
||||||
if (hclass->value == searchword) {
|
|
||||||
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);
|
|
||||||
// Use first node found
|
|
||||||
if (elemvect.size() > 0) {
|
|
||||||
return elemvect[0];
|
|
||||||
}
|
|
||||||
// If no nodes were found, panic()
|
|
||||||
throw parsingNoSuchIDError();
|
|
||||||
}
|
|
||||||
|
|
||||||
void gumbo_search_by_tag(std::vector<GumboNode *> &elemvect, GumboNode* node, GumboTag searchedtag) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string gumbo_cleantext(GumboNode* node) {
|
|
||||||
if (node->type == GUMBO_NODE_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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return contents;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> gumbo_get_attr(GumboNode *node, std::string attrkey, GumboTag expected_tag) {
|
|
||||||
std::vector<std::string> attrvals;
|
|
||||||
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]);
|
|
||||||
if (childnode->v.element.tag == expected_tag) { // If node is the expected tag; use it
|
|
||||||
attrvals.push_back(gumbo_get_attribute(&childnode->v.element.attributes, attrkey.c_str())->value);
|
|
||||||
} else if (childnode->type == GUMBO_NODE_ELEMENT) { // Else; iterate through its child nodes
|
|
||||||
toappend = gumbo_get_attr(childnode, attrkey, expected_tag);
|
|
||||||
attrvals = merge_strvects(attrvals, toappend);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the final result
|
|
||||||
return attrvals;
|
|
||||||
}
|
|
||||||
|
|
||||||
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]);
|
|
||||||
if (childnode->v.element.tag == searchtag) { // If node is the expected tag; check content
|
|
||||||
return trim(gumbo_cleantext(childnode));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw parsingNoSuchTagError();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
auto get_posts(GumboNode *node) {
|
|
||||||
std::vector<GumboNode *> posts;
|
|
||||||
gumbo_search_by_class(posts, node, "uk-comment", GUMBO_TAG_ARTICLE);
|
|
||||||
return posts;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string get_post_name(GumboNode *node) {
|
|
||||||
std::vector<GumboNode *> titlenodes;
|
|
||||||
gumbo_search_by_class(titlenodes, node, "uk-comment-title", GUMBO_TAG_H4);
|
|
||||||
return trim(gumbo_cleantext(titlenodes[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string get_post_id(GumboNode *node) {
|
|
||||||
return gumbo_get_attr(node, "data-item-id", GUMBO_TAG_ARTICLE)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string get_post_meta(GumboNode *node) {
|
|
||||||
std::vector<GumboNode *> metanodes;
|
|
||||||
gumbo_search_by_class(metanodes, node, "uk-comment-meta", GUMBO_TAG_DIV);
|
|
||||||
return clean_spaces(trim(gumbo_cleantext(metanodes[1])));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string get_post_url(GumboNode *node) {
|
|
||||||
std::vector<GumboNode *> titlenodes;
|
|
||||||
gumbo_search_by_class(titlenodes, node, "uk-comment-title", GUMBO_TAG_H4);
|
|
||||||
return gumbo_get_attr(titlenodes[0], "href", GUMBO_TAG_A)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get_post_unread(GumboNode *node) {
|
|
||||||
std::vector<GumboNode *> elems;
|
|
||||||
gumbo_search_by_class(elems, node, "cs-comment-change-info", GUMBO_TAG_DIV);
|
|
||||||
return !elems.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
taskState::type get_post_taskState(GumboNode *node) {
|
|
||||||
// Find all elements that could contain the information we need and grab their "class" attribute
|
|
||||||
std::vector<std::string> divClassAttrs;
|
|
||||||
divClassAttrs = gumbo_get_attr(node, "class", GUMBO_TAG_I);
|
|
||||||
|
|
||||||
// Try to find the information we need
|
|
||||||
for (const auto& classAttr : divClassAttrs) {
|
|
||||||
if (classAttr.find("todo") != std::string::npos) {
|
|
||||||
return taskState::todo;
|
|
||||||
} else if (classAttr.find("inProgress") != std::string::npos) {
|
|
||||||
return taskState::inProgress;
|
|
||||||
} else if (classAttr.find("done") != std::string::npos) {
|
|
||||||
return taskState::done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return taskState::none;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::map<std::string, std::string>> get_post_files(GumboNode *node) {
|
|
||||||
std::vector<GumboNode *> metanodes;
|
|
||||||
std::vector<std::string> fileurls;
|
|
||||||
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;
|
|
||||||
// Append it to the result vector map
|
|
||||||
filenameurlmap.push_back(tmpmap);
|
|
||||||
// Get next item in both vectors
|
|
||||||
urlit++; nameit++;
|
|
||||||
}
|
|
||||||
return filenameurlmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string get_post_desc(std::string post_url) {
|
|
||||||
std::string material_id;
|
|
||||||
std::stringstream httpcontent;
|
|
||||||
GumboOutput *post_document;
|
|
||||||
GumboNode *desc_node;
|
|
||||||
std::vector<GumboNode *> results;
|
|
||||||
|
|
||||||
// Get material ID
|
|
||||||
material_id = get_filename(post_url);
|
|
||||||
// Download post
|
|
||||||
long statuscode = curlreq(httpcontent, server_sid, post_url);
|
|
||||||
// Check statuscode
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct commsyFile {
|
struct commsyFile {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string url;
|
std::string url;
|
||||||
|
@ -357,115 +33,17 @@ public:
|
||||||
unsigned long numposts;
|
unsigned long numposts;
|
||||||
std::string lastID;
|
std::string lastID;
|
||||||
|
|
||||||
bool postExists(unsigned long postID) {
|
bool postExists(unsigned long postID);
|
||||||
return postID < numposts;
|
|
||||||
}
|
|
||||||
|
|
||||||
commsyPost *getPost(unsigned long postID) {
|
commsyPost *getPost(unsigned long postID);
|
||||||
// Check if post exists
|
|
||||||
if (not postExists(postID)) {
|
|
||||||
throw invalidPostError();
|
|
||||||
}
|
|
||||||
// Return post pointer
|
|
||||||
return &posts[postID];
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string *getDescription(unsigned long postID) {
|
std::string *getDescription(unsigned long postID);
|
||||||
// Get post
|
|
||||||
commsyPost *thispost = getPost(postID);
|
|
||||||
|
|
||||||
// Check if post description was downloaded already
|
libCommsy(const std::string& _server_url, const std::string& _server_sid, const std::string& _room, const std::string start_id = "", const unsigned long max_posts = 0);
|
||||||
if (thispost->description == "\xFF") {
|
|
||||||
// Download post
|
|
||||||
thispost->description = get_post_desc(server_url + thispost->url);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return it
|
// Exceptions
|
||||||
return &thispost->description;
|
class invalidSIDError {};
|
||||||
}
|
class invalidRoomError {};
|
||||||
|
class invalidPostError {};
|
||||||
libCommsy(const std::string& _server_url, const std::string& _server_sid, const std::string& _room, const std::string start_id = "", const unsigned long max_posts = 0) {
|
class connectionFailError {};
|
||||||
// Define required variables
|
|
||||||
server_url = _server_url;
|
|
||||||
server_sid = _server_sid;
|
|
||||||
room = _room;
|
|
||||||
lastID = start_id;
|
|
||||||
std::stringstream httpcontent;
|
|
||||||
GumboOutput *document;
|
|
||||||
long statuscode;
|
|
||||||
numposts = 0;
|
|
||||||
|
|
||||||
// Loop until all or max_posts posts are fetched
|
|
||||||
while (1) {
|
|
||||||
// Check connection and download feed
|
|
||||||
try {
|
|
||||||
statuscode = curlreq(httpcontent, server_sid, server_url + "/room/" + room + "/feed/10/date?lastId=" + lastID);
|
|
||||||
} catch (std::exception&) {
|
|
||||||
throw connectionFailError();
|
|
||||||
}
|
|
||||||
if (statuscode == 302) {
|
|
||||||
throw invalidSIDError();
|
|
||||||
} else if (statuscode == 500) {
|
|
||||||
throw invalidRoomError();
|
|
||||||
} else if (statuscode != 200) {
|
|
||||||
std::cout << "Unhandled status code " << statuscode << std::endl;
|
|
||||||
throw connectionFailError();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
commsyPost thispost;
|
|
||||||
{
|
|
||||||
// Get posts name
|
|
||||||
thispost.name = get_post_name(*it);
|
|
||||||
// Get posts ID
|
|
||||||
thispost.id = get_post_id(*it);
|
|
||||||
// Get posts meta string
|
|
||||||
thispost.meta = get_post_meta(*it);
|
|
||||||
// Get if post is unread
|
|
||||||
thispost.unread = get_post_unread(*it);
|
|
||||||
// Get posts task state
|
|
||||||
thispost.taskState = get_post_taskState(*it);
|
|
||||||
// Get posts URL
|
|
||||||
thispost.url = get_post_url(*it);
|
|
||||||
// Get posts files
|
|
||||||
auto files = get_post_files(*it);
|
|
||||||
for (const auto& filemap : files) {
|
|
||||||
for (const auto& [filename, fileurl] : filemap) {
|
|
||||||
commsyFile thisfile;
|
|
||||||
{
|
|
||||||
thisfile.name = filename;
|
|
||||||
thisfile.url = fileurl;
|
|
||||||
}
|
|
||||||
thispost.files.push_back(thisfile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append to posts vector
|
|
||||||
posts.push_back(thispost);
|
|
||||||
// Increment post counter
|
|
||||||
numposts++;
|
|
||||||
// Get lastID
|
|
||||||
lastID = posts.back().id;
|
|
||||||
// Check if maximum amount of posts to load was exceeded
|
|
||||||
if (numposts == max_posts) {
|
|
||||||
// Stop loading more posts
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,7 +29,7 @@ public:
|
||||||
QNetworkAccessManager *mNetManAuth = nullptr;
|
QNetworkAccessManager *mNetManAuth = nullptr;
|
||||||
QNetworkRequest *mNetReq = nullptr;
|
QNetworkRequest *mNetReq = nullptr;
|
||||||
|
|
||||||
explicit libCommsyAuth(QObject *p = nullptr) : QObject (p){
|
libCommsyAuth(QObject *p = nullptr) : QObject (p){
|
||||||
mNetManTestconn = new QNetworkAccessManager(this);
|
mNetManTestconn = new QNetworkAccessManager(this);
|
||||||
mNetManAuth = new QNetworkAccessManager(this);
|
mNetManAuth = new QNetworkAccessManager(this);
|
||||||
mNetReq = new QNetworkRequest();
|
mNetReq = new QNetworkRequest();
|
||||||
|
|
107
main.cpp
107
main.cpp
|
@ -33,8 +33,6 @@
|
||||||
#define QCommsy_NAME "QCommsy"
|
#define QCommsy_NAME "QCommsy"
|
||||||
#define QCommsy_VERSION "1.1-dev"
|
#define QCommsy_VERSION "1.1-dev"
|
||||||
|
|
||||||
#define UPDATE_WINDOW(a) a->processEvents();
|
|
||||||
|
|
||||||
static QSettings *settings;
|
static QSettings *settings;
|
||||||
static QApplication *a;
|
static QApplication *a;
|
||||||
static QMainWindow *w;
|
static QMainWindow *w;
|
||||||
|
@ -201,7 +199,7 @@ void _UILoader::loginWindow(const QString& failure) {
|
||||||
return overviewWindow(false);
|
return overviewWindow(false);
|
||||||
} catch (authFailureError&) {
|
} catch (authFailureError&) {
|
||||||
thisui->failureText->setText("Die eingegebenen Anmeldedaten sind ungültig");
|
thisui->failureText->setText("Die eingegebenen Anmeldedaten sind ungültig");
|
||||||
} catch (invalidRoomError&) {
|
} catch (libCommsy::invalidRoomError&) {
|
||||||
thisui->failureText->setText("Der angegebene Raum existiert nicht");
|
thisui->failureText->setText("Der angegebene Raum existiert nicht");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -286,6 +284,30 @@ void _UILoader::postViewWindow(commsyPost *thispost, QString description) {
|
||||||
void _UILoader::overviewWindow(bool catchInvalidRoomError) {
|
void _UILoader::overviewWindow(bool catchInvalidRoomError) {
|
||||||
Ui::overviewWindow *thisui = new Ui::overviewWindow;
|
Ui::overviewWindow *thisui = new Ui::overviewWindow;
|
||||||
|
|
||||||
|
// Following code is blocking
|
||||||
|
a->processEvents();
|
||||||
|
|
||||||
|
// Connect if required
|
||||||
|
try {
|
||||||
|
reconnect();
|
||||||
|
} catch (libCommsy::invalidSIDError&) {
|
||||||
|
logout();
|
||||||
|
return loginWindow("Die Sitzung ist abgelaufen - bitte erneut anmelden");
|
||||||
|
} catch (libCommsy::invalidRoomError& exception) {
|
||||||
|
|
||||||
|
if (catchInvalidRoomError) {
|
||||||
|
logout();
|
||||||
|
return loginWindow("Der Raum existiert nicht mehr");
|
||||||
|
} else {
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (libCommsy::connectionFailError&) {
|
||||||
|
return offlineWindow();
|
||||||
|
} catch (std::exception&) {
|
||||||
|
return failureWindow();
|
||||||
|
}
|
||||||
|
|
||||||
// Show initial UI
|
// Show initial UI
|
||||||
thisui->setupUi(w);
|
thisui->setupUi(w);
|
||||||
w->show();
|
w->show();
|
||||||
|
@ -298,68 +320,43 @@ void _UILoader::overviewWindow(bool catchInvalidRoomError) {
|
||||||
thispost->unread = false; // Mark post as read locally
|
thispost->unread = false; // Mark post as read locally
|
||||||
|
|
||||||
// Run blocking code
|
// Run blocking code
|
||||||
UPDATE_WINDOW(a) {
|
a->processEvents();
|
||||||
postViewWindow(thispost, QString::fromStdString(*connector->getDescription(postID)));
|
postViewWindow(thispost, QString::fromStdString(*connector->getDescription(postID)));
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
w->connect(thisui->logoutButton, &QPushButton::pressed, [this] () { logout(); loginWindow(); });
|
w->connect(thisui->logoutButton, &QPushButton::pressed, [this] () { logout(); loginWindow(); });
|
||||||
w->connect(thisui->infoButton, &QPushButton::pressed, [this] () { infoWindow(); });
|
w->connect(thisui->infoButton, &QPushButton::pressed, [this] () { infoWindow(); });
|
||||||
|
|
||||||
// Run blocking code
|
// Get font used for unread posts
|
||||||
UPDATE_WINDOW(a) {
|
QFont unreadFont = QFont();
|
||||||
// Connect if required
|
unreadFont.setBold(true);
|
||||||
try {
|
|
||||||
reconnect();
|
|
||||||
} catch (invalidSIDError&) {
|
|
||||||
logout();
|
|
||||||
return loginWindow("Die Sitzung ist abgelaufen - bitte erneut anmelden");
|
|
||||||
} catch (invalidRoomError& exception) {
|
|
||||||
|
|
||||||
if (catchInvalidRoomError) {
|
// Refresh view
|
||||||
logout();
|
thisui->postCounter->setText(QString::number(connector->numposts) + " Einträge");
|
||||||
return loginWindow("Der Raum existiert nicht mehr");
|
thisui->postList->clear();
|
||||||
} else {
|
for (const auto& thispost : connector->posts) {
|
||||||
throw exception;
|
QListWidgetItem *thisitem = new QListWidgetItem(QString::fromStdString(thispost.name), thisui->postList);
|
||||||
}
|
|
||||||
|
|
||||||
} catch (connectionFailError&) {
|
if (thispost.unread) {
|
||||||
return offlineWindow();
|
thisitem->setFont(unreadFont);
|
||||||
} catch (std::exception&) {
|
|
||||||
return failureWindow();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get font used for unread posts
|
QString postIcon;
|
||||||
QFont unreadFont = QFont();
|
switch(thispost.taskState) {
|
||||||
unreadFont.setBold(true);
|
case taskState::done:
|
||||||
|
postIcon = "checkbox-checked-symbolic";
|
||||||
// Refresh view
|
break;
|
||||||
thisui->postCounter->setText(QString::number(connector->numposts) + " Einträge");
|
case taskState::inProgress:
|
||||||
thisui->postList->clear();
|
postIcon = "clock";
|
||||||
for (const auto& thispost : connector->posts) {
|
break;
|
||||||
QListWidgetItem *thisitem = new QListWidgetItem(QString::fromStdString(thispost.name), thisui->postList);
|
case taskState::todo:
|
||||||
|
postIcon = "emblem-important-symbolic";
|
||||||
if (thispost.unread) {
|
break;
|
||||||
thisitem->setFont(unreadFont);
|
default:
|
||||||
}
|
postIcon = "arrow-right";
|
||||||
|
break;
|
||||||
QString postIcon;
|
|
||||||
switch(thispost.taskState) {
|
|
||||||
case taskState::done:
|
|
||||||
postIcon = "checkbox-checked-symbolic";
|
|
||||||
break;
|
|
||||||
case taskState::inProgress:
|
|
||||||
postIcon = "clock";
|
|
||||||
break;
|
|
||||||
case taskState::todo:
|
|
||||||
postIcon = "emblem-important-symbolic";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
postIcon = "arrow-right";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
thisitem->setIcon(QIcon::fromTheme(postIcon));
|
|
||||||
}
|
}
|
||||||
|
thisitem->setIcon(QIcon::fromTheme(postIcon));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue