mirror of
https://gitlab.com/niansa/qcommsy.git
synced 2025-03-06 20:53:33 +01:00
406 lines
14 KiB
C++
406 lines
14 KiB
C++
/*
|
|
QCommsy
|
|
Copyright (C) 2020 niansa
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "ui_overview.h"
|
|
#include "ui_info.h"
|
|
#include "ui_login.h"
|
|
#include "ui_failure.h"
|
|
#include "ui_offline.h"
|
|
#include "ui_postView.h"
|
|
#include "libcommsy.hpp"
|
|
#include "libcommsyauth.hpp"
|
|
|
|
#include <limits.h>
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <functional>
|
|
|
|
#include <QMainWindow>
|
|
#include <QApplication>
|
|
#include <QPushButton>
|
|
#include <QString>
|
|
#include <QUrl>
|
|
#include <QDir>
|
|
#include <QFile>
|
|
#include <QTimer>
|
|
#include <QMainWindow>
|
|
#include <QListWidgetItem>
|
|
#include <QFont>
|
|
#include <QStyleFactory>
|
|
#include <QDesktopServices>
|
|
#include <QSettings>
|
|
#include <QNetworkAccessManager>
|
|
#include <QNetworkReply>
|
|
#include <QNetworkRequest>
|
|
|
|
#define QCommsy_NAME "QCommsy"
|
|
#define QCommsy_VERSION "1.1-dev"
|
|
|
|
static QSettings *settings;
|
|
static QApplication *a;
|
|
static QMainWindow *w;
|
|
|
|
|
|
class _UILoader {
|
|
libCommsy *connector = nullptr;
|
|
libCommsyAuth *auther = nullptr;
|
|
bool cacheInvalidate = true;
|
|
|
|
public:
|
|
void failureWindow();
|
|
void overviewWindow(bool catchInvalidRoomError = true);
|
|
void loginWindow(const QString& failure = "");
|
|
void infoWindow();
|
|
void postViewWindow(commsyPost *thispost, QString description);
|
|
void offlineWindow();
|
|
|
|
_UILoader () {
|
|
auther = new libCommsyAuth();
|
|
}
|
|
|
|
void reconnect() {
|
|
// Destroy old connector
|
|
if (connector != nullptr) {
|
|
if (not cacheInvalidate) {
|
|
return;
|
|
}
|
|
delete connector;
|
|
connector = nullptr;
|
|
}
|
|
cacheInvalidate = false;
|
|
// Connect to commsy
|
|
connector = new libCommsy(settings->value("server_url").toString().toStdString(), settings->value("server_sid").toString().toStdString(), settings->value("server_room").toString().toStdString());
|
|
}
|
|
|
|
void logout() {
|
|
settings->remove("server_sid");
|
|
}
|
|
|
|
void downloadAndOpenFile(QNetworkRequest mNetReq, const QString& filename) {
|
|
auto mNetMan = new QNetworkAccessManager();
|
|
|
|
// Set SID in request so we're authenticated TODO: think about a cleaner way
|
|
mNetReq.setRawHeader("Cookie", "SID=" + settings->value("server_sid").toString().toUtf8());
|
|
|
|
// Connect to downloading
|
|
w->connect(mNetMan, &QNetworkAccessManager::finished, [this, mNetMan, filename] (QNetworkReply *mNetReply) {
|
|
// Save and open downloaded file
|
|
{
|
|
// Initialise
|
|
QString destPath = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + '/' + filename;
|
|
QFile destFile(destPath);
|
|
|
|
// Write downloaded data to file
|
|
if (!destFile.open(QIODevice::WriteOnly)) {
|
|
return failureWindow();
|
|
}
|
|
destFile.write(mNetReply->readAll());
|
|
destFile.close();
|
|
|
|
// Open file in some application
|
|
//QDesktopServices::openUrl(destPath);
|
|
QDesktopServices::openUrl(QUrl::fromLocalFile(destPath));
|
|
}
|
|
|
|
// Clean up
|
|
mNetMan->deleteLater();
|
|
});
|
|
|
|
// Start download
|
|
mNetMan->get(mNetReq);
|
|
}
|
|
|
|
};
|
|
|
|
void _UILoader::infoWindow() {
|
|
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 "<br />"
|
|
"<b>Git version:</b> " GIT_CURRENT_SHA1 "<br />"
|
|
"<b>Build ID:</b> " + QString::number(std::hash<std::string>{}(__DATE__ __TIME__)) + "<br />"
|
|
);
|
|
thisui->buildDateInfo->setText(
|
|
"Build date:\n"
|
|
__DATE__ " " __TIME__
|
|
);
|
|
|
|
// Add button handlers
|
|
w->connect(thisui->backButton, &QPushButton::pressed, [this] () { loginWindow(); });
|
|
}
|
|
|
|
void _UILoader::failureWindow() {
|
|
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] () { loginWindow(); });
|
|
w->connect(thisui->logoutButton, &QPushButton::pressed, [this] () { logout(); loginWindow(); });
|
|
}
|
|
|
|
void _UILoader::offlineWindow() {
|
|
Ui::offlineWindow *thisui = new Ui::offlineWindow;
|
|
|
|
// Show initial UI
|
|
thisui->setupUi(w);
|
|
w->show();
|
|
// Add button handlers
|
|
w->connect(thisui->logoutButton, &QPushButton::pressed, [this] () { logout(); loginWindow(); });
|
|
}
|
|
|
|
void _UILoader::loginWindow(const QString& failure) {
|
|
Ui::loginWindow *thisui = new Ui::loginWindow;
|
|
|
|
// Check if logged in already
|
|
if (settings->contains("server_sid")) {
|
|
return overviewWindow();
|
|
}
|
|
|
|
// 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);
|
|
thisui->adressLine->setText(settings->value("server_url", thisui->adressLine->text()).toString());
|
|
thisui->roomLine->setText(settings->value("server_room", "").toString());
|
|
thisui->usernameLine->setText(settings->value("server_username", "").toString());
|
|
thisui->passwordLine->setText(settings->value("server_password", "").toString());
|
|
}
|
|
|
|
// Set failure text
|
|
thisui->failureText->setText(failure);
|
|
|
|
// Connect connection handlers
|
|
w->connect(auther, &libCommsyAuth::authDone, [thisui] (QNetworkReply *) { // Finished authentication; reenable login button
|
|
thisui->loginButton->setDisabled(false);
|
|
});
|
|
w->connect(auther, &libCommsyAuth::authDone, [this, thisui] (QNetworkReply *netReply) { // Finished authentication; try to login
|
|
// Login
|
|
try {
|
|
settings->setValue("server_sid", auther->getSID(netReply));
|
|
cacheInvalidate = true;
|
|
overviewWindow(false);
|
|
auther->deleteLater();
|
|
} catch (authFailureError&) {
|
|
thisui->failureText->setText("Die eingegebenen Anmeldedaten sind ungültig");
|
|
} catch (libCommsy::invalidRoomError&) {
|
|
thisui->failureText->setText("Der angegebene Raum existiert nicht");
|
|
}
|
|
});
|
|
w->connect(auther, &libCommsyAuth::connectionDone, [this, thisui] (QNetworkReply *netReply) { // Finished test connection
|
|
auther->sendAuth(auther->getAuthUrl(netReply), thisui->usernameLine->text(), thisui->passwordLine->text());
|
|
});
|
|
|
|
// Add button handlers
|
|
w->connect(thisui->loginButton, &QPushButton::pressed, [this, thisui] () {
|
|
// Check input lines
|
|
if (thisui->adressLine->text().isEmpty() or thisui->usernameLine->text().isEmpty() or thisui->roomLine->text().isEmpty() or thisui->passwordLine->text().isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
// Make sure the adressLine doesn't end with /
|
|
if (thisui->adressLine->text().endsWith("/")) {
|
|
thisui->adressLine->backspace();
|
|
}
|
|
|
|
// Save basic server credentials
|
|
bool saveAllData = thisui->saveBox->checkState() == Qt::Checked;
|
|
settings->setValue("server_save", saveAllData);
|
|
settings->setValue("server_url", thisui->adressLine->text());
|
|
settings->setValue("server_room", thisui->roomLine->text());
|
|
if (saveAllData) {
|
|
settings->setValue("server_username", thisui->usernameLine->text());
|
|
settings->setValue("server_password", thisui->passwordLine->text());
|
|
}
|
|
|
|
// Disable login button
|
|
thisui->loginButton->setDisabled(true);
|
|
|
|
// Connect
|
|
auther->connectionInit(thisui->adressLine->text());
|
|
});
|
|
}
|
|
|
|
void _UILoader::postViewWindow(commsyPost *thispost, QString description) {
|
|
Ui::postViewWindow *thisui = new Ui::postViewWindow;
|
|
|
|
// Show initial UI
|
|
thisui->setupUi(w);
|
|
w->show();
|
|
thisui->statusText->setVisible(false);
|
|
|
|
// Remove trailing space from description
|
|
if (description.size() != 0 and description.back() == '\n') {
|
|
description.chop(1);
|
|
}
|
|
|
|
// Update informations
|
|
thisui->titleText->setText(QString::fromStdString(thispost->name));
|
|
thisui->metaText->setText(QString::fromStdString(thispost->meta));
|
|
thisui->descriptionText->setText(description);
|
|
|
|
// Update file list if required
|
|
if (thispost->files.size() != 0) {
|
|
for (const auto& thisfile : thispost->files) {
|
|
thisui->fileList->addItem(QString::fromStdString(thisfile.name));
|
|
}
|
|
} else { // If no files exist, hide the list
|
|
thisui->filesInfo->setHidden(true);
|
|
thisui->fileList->setHidden(true);
|
|
}
|
|
|
|
// Add button handlers
|
|
w->connect(thisui->fileList, &QListWidget::activated, [this, thisui, thispost] (QModelIndex index) {
|
|
// Get full file URL
|
|
commsyFile *thisfile = &thispost->files[static_cast<unsigned long>(index.row())];
|
|
QUrl fullFileUrl(settings->value("server_url").toString() + QString::fromStdString(thisfile->url));
|
|
|
|
// Start download
|
|
downloadAndOpenFile(QNetworkRequest(fullFileUrl), QString::fromStdString(thisfile->name));
|
|
|
|
// Show download status für 5 seconds
|
|
thisui->statusText->setVisible(true);
|
|
QTimer::singleShot(5 * 1000, thisui->statusText, &QLabel::hide);
|
|
});
|
|
w->connect(thisui->backButton, &QPushButton::pressed, [this] () { loginWindow(); });
|
|
}
|
|
|
|
void _UILoader::overviewWindow(bool catchInvalidRoomError) {
|
|
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
|
|
thisui->setupUi(w);
|
|
w->show();
|
|
|
|
// Add button handlers
|
|
w->connect(thisui->postList, &QListWidget::activated, [this, thisui] (QModelIndex index) {
|
|
auto postID = static_cast<unsigned long>(index.row());
|
|
commsyPost *thispost = connector->getPost(postID);
|
|
thisui->centralwidget->setDisabled(true);
|
|
thispost->unread = false; // Mark post as read locally
|
|
|
|
// Run blocking code
|
|
a->processEvents();
|
|
postViewWindow(thispost, QString::fromStdString(*connector->getDescription(postID)));
|
|
});
|
|
|
|
w->connect(thisui->logoutButton, &QPushButton::pressed, [this] () { logout(); loginWindow(); });
|
|
w->connect(thisui->infoButton, &QPushButton::pressed, [this] () { infoWindow(); });
|
|
|
|
// Get font used for unread posts
|
|
QFont unreadFont = QFont();
|
|
unreadFont.setBold(true);
|
|
|
|
// Refresh view
|
|
thisui->postCounter->setText(QString::number(connector->numposts) + " Einträge");
|
|
thisui->postList->clear();
|
|
for (const auto& thispost : connector->posts) {
|
|
QListWidgetItem *thisitem = new QListWidgetItem(QString::fromStdString(thispost.name), thisui->postList);
|
|
|
|
if (thispost.unread) {
|
|
thisitem->setFont(unreadFont);
|
|
}
|
|
|
|
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));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) {
|
|
// Initalise settings storage
|
|
QCoreApplication::setOrganizationName("QCommsy");
|
|
QCoreApplication::setOrganizationDomain("qcommsy.github.io");
|
|
QCoreApplication::setApplicationName("QCommsy");
|
|
settings = new QSettings();
|
|
|
|
//Initialise variables
|
|
a = new QApplication(argc, argv);
|
|
w = new QMainWindow;
|
|
_UILoader UILoader;
|
|
|
|
// Set theme
|
|
a->setStyle(QStyleFactory::create("android"));
|
|
|
|
// Load initial window
|
|
UILoader.loginWindow();
|
|
|
|
// Run forever
|
|
return a->exec();
|
|
}
|