/* blueROCK - for digital rock Copyright (C) 2019 Dorian Zedler 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 . */ #include "headers/bluerockbackend.h" BlueRockBackend::BlueRockBackend(QObject *parent) : QObject(parent), _pendingIntentsChecked(false) { this->_shareUtils = new ShareUtils(this); connect(this->_shareUtils, &ShareUtils::otherUrlReceived, this, &BlueRockBackend::openedViaUrl); #if defined(Q_OS_ANDROID) connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(onApplicationStateChanged(Qt::ApplicationState))); #elif defined Q_OS_IOS this->_iosPermissionUtils = new IosPermissionUtils(); #endif } QVariant BlueRockBackend::getWidgetData(QVariantMap params) { QString requestUrl = "https://www.digitalrock.de/egroupware/ranking/json.php?"; QStringList nations = {"ICC", "GER", "SUI"}; if(params["nation"].toString() == "ICC") { params["nation"] = ""; } else if(params["nation"].toString() == "") { params.remove("nation"); } else if(!nations.contains(params["nation"].toString())) { // a non-empty nation which ist not one of the above is invalid return QVariantMap({{"status", 404}}); } for(QVariantMap::const_iterator iter = params.begin(); iter != params.end(); ++iter) { requestUrl += iter.key() + "=" + iter.value().toString() + "&"; } requestUrl = requestUrl.left(requestUrl.length() - 1); // remove last '&' qWarning() << requestUrl; QVariantMap ret = this->_senddata(QUrl(requestUrl)); if(ret["status"] != 200) { // request was a failure return QVariantMap({{"status", ret["status"]}, {"data", ""}}); } QJsonDocument jsonReply = QJsonDocument::fromJson(ret["text"].toString().toUtf8()); QVariantMap data = {{"status", 200}, {"data", jsonReply.toVariant()}}; return data; } QVariantMap BlueRockBackend::getParamsFromUrl(QString stringUrl) { stringUrl = stringUrl.replace("#!", "?"); QUrl url(stringUrl); if(!url.isValid() || url.isEmpty() || url.host().isEmpty()) return {{"valid", false},{"params", QVariantMap()}} ; QStringList domainFragments = url.host().split("."); QString tld = domainFragments.takeLast(); QString domainName = domainFragments.takeLast(); QString baseDomain = domainName + "." + tld; if(!this->_validBaseDomains.contains(baseDomain)) return {{"valid", false},{"params", QVariantMap()}}; QUrlQuery query(url.query()); QVariantMap params; for(QPair pair : query.queryItems()) { if(params.contains(pair.first)) params[pair.first] = pair.second; else params.insert(pair.first, pair.second); } return {{"valid", true},{"params",params}}; } void BlueRockBackend::shareResultsAsUrl(QString url, QString compName) { //% "Check out the results of %1 over here:" this->_shareUtils->shareText(qtTrId("#shareResultsLinkText").arg(compName) + " \n", url); } void BlueRockBackend::shareResultsAsPoster(QString url, QString compName) { QString path = this->_shareUtils->getTemporaryFileLocationPath(); //QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); if (!QDir(path).exists()) { if (QDir("").mkpath(path)) { qDebug() << "Created app data /files directory. " << path; } else { qWarning() << "Failed to create app data /files directory. " << path; return; } } QString rawCompName = compName; QString escapedCompName = compName.replace("/", " "); path += "/" + escapedCompName + ".pdf"; QFile file(path); file.remove(); if(!file.open(QIODevice::ReadWrite)) { qWarning("Could not open File for writing!!"); return; } // dimensions QRect qrCodeRect = QRect(414, 414, 1650, 1650); int compNameTextLineHeight = 64; QFont compNameTextFont("OpenSans-Light"); compNameTextFont.setPixelSize(compNameTextLineHeight); QRect compNameTextRect = QRect( 324, 2500, 1835, 150 ); QPdfWriter writer(&file); writer.setPageSize(QPageSize(QPageSize::A4)); writer.setPageMargins(QMargins(0, 0, 0, 0)); writer.setResolution(300); QPainter painter(&writer); QPixmap posterTemplate(":/PosterTemplate.png"); painter.drawPixmap(0,0, writer.width(), writer.height(), posterTemplate); QPixmap barcode; QZXingEncoderConfig encoderConfig(QZXing::EncoderFormat_QR_CODE, qrCodeRect.size(), QZXing::EncodeErrorCorrectionLevel_H, false, false); barcode.convertFromImage(QZXing::encodeData(url, encoderConfig)); painter.drawPixmap(qrCodeRect, barcode); painter.setFont(compNameTextFont); painter.setPen(Qt::black); painter.drawText(compNameTextRect, Qt::AlignLeft|Qt::AlignBottom|Qt::TextWordWrap, rawCompName); painter.end(); file.close(); this->_shareUtils->sendFile(path, escapedCompName, "application/pdf", 1); } bool BlueRockBackend::isCameraPermissionGranted() { #ifdef Q_OS_ANDROID QtAndroid::PermissionResult cameraAccess = QtAndroid::checkPermission("android.permission.CAMERA"); return cameraAccess == QtAndroid::PermissionResult::Granted; #elif defined Q_OS_IOS return this->_iosPermissionUtils->isCameraPermissionGranted(); #else return true; #endif } bool BlueRockBackend::requestCameraPermission() { if(this->isCameraPermissionGranted()) return true; #ifdef Q_OS_ANDROID // try to get permission QtAndroid::PermissionResultMap resultMap = QtAndroid::requestPermissionsSync({"android.permission.CAMERA"}); bool resultBool = true; for(QtAndroid::PermissionResult result : resultMap) { if(result != QtAndroid::PermissionResult::Granted) { resultBool = false; } } if(resultBool) { return true; } // getting permission the traditional way failed -> open the settings app QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); if (activity.isValid()) { // get the package name QAndroidJniObject context = QtAndroid::androidContext(); QAndroidJniObject applicationPackageName = context.callObjectMethod("getPackageName"); QAndroidJniObject param = QAndroidJniObject::fromString("package:" + applicationPackageName.toString()); // Equivalent to Jave code: 'Uri uri = Uri::parse("...");' QAndroidJniObject uri = QAndroidJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", param.object()); if (!uri.isValid()) { qWarning("ERROR: Unable to create Uri object"); return false; } QAndroidJniObject packageName = QAndroidJniObject::fromString("android.settings.APPLICATION_DETAILS_SETTINGS"); QAndroidJniObject intent("android/content/Intent","(Ljava/lang/String;)V", packageName.object()); if (!intent.isValid()) { qWarning("ERROR: Unable to create Intent object"); return false; } intent.callObjectMethod("addCategory", "(Ljava/lang/String;)Landroid/content/Intent;", QAndroidJniObject::fromString("android.intent.category.DEFAULT").object()); intent.callObjectMethod("setData", "(Landroid/net/Uri;)Landroid/content/Intent;", uri.object()); activity.callMethod("startActivity","(Landroid/content/Intent;)V",intent.object()); } else { qWarning() << "ERROR: Activity not valid!"; return false; } return false; #elif defined Q_OS_IOS return this->_iosPermissionUtils->requestCameraPermission(); #else return true; #endif } // ------------------------ // --- Helper functions --- // ------------------------ QVariantMap BlueRockBackend::_senddata(QUrl serviceUrl, QUrlQuery pdata) { // create network manager QNetworkAccessManager * networkManager = new QNetworkAccessManager(); QVariantMap ret; //this is a custom type to store the return-data // Create network request QNetworkRequest request(serviceUrl); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); //QSslConfiguration config = QSslConfiguration::defaultConfiguration(); //config.setProtocol(QSsl::TlsV1_2); //request.setSslConfiguration(config); //send a POST request with the given url and data to the server QNetworkReply *reply; if(pdata.isEmpty()) { // if no post data is given -> send a GET request reply = networkManager->get(request); } else { // if post data is given -> send POST request reply = networkManager->post(request, pdata.toString(QUrl::FullyEncoded).toUtf8()); } // loop to wait until the request has finished before processing the data QEventLoop loop; // timer to cancel the request after 3 seconds QTimer timer; timer.setSingleShot(true); // quit the loop when the request finised loop.connect(networkManager, SIGNAL(finished(QNetworkReply*)), SLOT(quit())); // or the timer timed out loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); // start the timer timer.start(10000); // start the loop loop.exec(); //get the status code QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); ret.insert("status", status_code.toInt()); //get the full text response ret.insert("text", QString::fromUtf8(reply->readAll())); // delete the reply object delete reply; // delete the newtwork access manager object delete networkManager; //return the data return(ret); } #if defined(Q_OS_ANDROID) void BlueRockBackend::onApplicationStateChanged(Qt::ApplicationState applicationState) { qDebug() << "S T A T E changed into: " << applicationState; if(applicationState == Qt::ApplicationState::ApplicationSuspended) { // nothing to do return; } if(applicationState == Qt::ApplicationState::ApplicationActive) { // if App was launched from VIEW or SEND Intent // there's a race collision: the event will be lost, // because App and UI wasn't completely initialized // workaround: QShareActivity remembers that an Intent is pending if(!_pendingIntentsChecked) { _pendingIntentsChecked = true; _shareUtils->checkPendingIntents(this->_shareUtils->getTemporaryFileLocationPath()); } } } #endif // ------------------------- // --- Functions for QML --- // -------------------------