void
CyclingAnalyticsUploader::requestUploadCyclingAnalytics()
{
    parent->progressLabel->setText(tr("Upload ride to CyclingAnalytics..."));
    parent->progressBar->setValue(parent->progressBar->value()+10/parent->shareSiteCount);

    QEventLoop eventLoop;
    QNetworkAccessManager networkMgr;

    connect(&networkMgr, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestUploadCyclingAnalyticsFinished(QNetworkReply*)));
    connect(&networkMgr, SIGNAL(finished(QNetworkReply *)), &eventLoop, SLOT(quit()));

    QUrl url = QUrl( "https://www.cyclinganalytics.com/api/me/upload" );
    QNetworkRequest request = QNetworkRequest(url);

    QString boundary = QVariant(qrand()).toString()+QVariant(qrand()).toString()+QVariant(qrand()).toString();

    TcxFileReader reader;
    QByteArray file = reader.toByteArray(context, ride->ride(), parent->altitudeChk->isChecked(), parent->powerChk->isChecked(), parent->heartrateChk->isChecked(), parent->cadenceChk->isChecked());

    // MULTIPART *****************

    QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
    multiPart->setBoundary(boundary.toLatin1());

    request.setRawHeader("Authorization", (QString("Bearer %1").arg(token)).toLatin1());

    QHttpPart activityNamePart;
    activityNamePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"title\""));
    activityNamePart.setBody(QString(parent->titleEdit->text()).toLatin1());

    QHttpPart dataTypePart;
    dataTypePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"format\""));
    dataTypePart.setBody("tcx");

    QHttpPart filenamePart;
    filenamePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"filename\""));
    filenamePart.setBody("file.tcx");

    QHttpPart filePart;
    filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"data\"; filename=\"file.tcx\"; type=\"text/xml\""));
    filePart.setBody(file);

    multiPart->append(activityNamePart);
    multiPart->append(filenamePart);
    multiPart->append(dataTypePart);
    multiPart->append(filePart);

    QScopedPointer<QNetworkReply> reply( networkMgr.post(request, multiPart) );
    multiPart->setParent(reply.data());

    parent->progressBar->setValue(parent->progressBar->value()+30/parent->shareSiteCount);
    parent->progressLabel->setText(tr("Upload ride... Sending to CyclingAnalytics"));

    eventLoop.exec();
}
/*
  make a multipart HTTP POST at the following path "/restapi/public/activities/upload.json"
  on selflloops web site using SSL.
  The requested parameters are:
   - "email" the email of a valid SelfLoops account
   - "pw" the password
   - "tcxfile" the zipped TCX file (example: test.tcx.gz).

   On success, response message contains a JSON encoded data
   with the new "activity_id" created.
   On error, SelfLoops response contains a JSON encoded data with "error_code" and "message" key.
*/
void
SelfLoopsUploader::requestUploadSelfLoops()
{
    parent->progressLabel->setText(tr("Upload ride to Selfloops..."));
    parent->progressBar->setValue(parent->progressBar->value()+10/parent->shareSiteCount);

    QEventLoop eventLoop;
    QNetworkAccessManager networkMgr;

    connect(&networkMgr, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestUploadSelfLoopsFinished(QNetworkReply*)));
    connect(&networkMgr, SIGNAL(finished(QNetworkReply *)), &eventLoop, SLOT(quit()));

    QUrl url = QUrl( "https://www.selfloops.com/restapi/public/activities/upload.json" );
    QNetworkRequest request = QNetworkRequest(url);

    QString boundary = QVariant(qrand()).toString()+QVariant(qrand()).toString()+QVariant(qrand()).toString();

    // The TCX file have to be gzipped
    TcxFileReader reader;
    QByteArray file = zCompress(reader.toByteArray(context, ride->ride(), parent->altitudeChk->isChecked(), parent->powerChk->isChecked(), parent->heartrateChk->isChecked(), parent->cadenceChk->isChecked()));

    QString username = appsettings->cvalue(context->athlete->cyclist, GC_SELUSER).toString();
    QString password = appsettings->cvalue(context->athlete->cyclist, GC_SELPASS).toString();

    // MULTIPART *****************

    QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::MixedType);
    multiPart->setBoundary(boundary.toLatin1());

    QHttpPart emailPart;
    emailPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"email\""));
    emailPart.setBody(username.toLatin1());

    QHttpPart passwordPart;
    passwordPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"pw\""));
    passwordPart.setBody(password.toLatin1());

    QHttpPart filePart;
    filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"tcxfile\"; filename=\"myfile.tcx.gz\"; type=\"application/x-gzip\""));
    filePart.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-gzip");
    filePart.setBody(file);

    multiPart->append(emailPart);
    multiPart->append(passwordPart);
    multiPart->append(filePart);

    QScopedPointer<QNetworkReply> reply( networkMgr.post(request, multiPart) );
    multiPart->setParent(reply.data());

    parent->progressBar->setValue(parent->progressBar->value()+30/parent->shareSiteCount);
    parent->progressLabel->setText(tr("Upload ride... Sending to Selfloops"));

    eventLoop.exec();
}
void
SportPlusHealthUploader::requestUpload()
{
    parent->progressLabel->setText(tr("sending to SportPlusHealth..."));
    parent->progressBar->setValue(parent->progressBar->value()+10/parent->shareSiteCount);

    QString username = appsettings->cvalue(context->athlete->cyclist, GC_SPORTPLUSHEALTHUSER).toString();
    QString password = appsettings->cvalue(context->athlete->cyclist, GC_SPORTPLUSHEALTHPASS).toString();

    //Building the message content
    QHttpMultiPart *body = new QHttpMultiPart( QHttpMultiPart::FormDataType );

    //Including the optional session name
    QHttpPart textPart;
    textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"session_name\""));
    textPart.setBody(QByteArray(insertedName.toLatin1()));
    body->append(textPart);

    //Including the content data type
    QHttpPart dataTypePart;
    dataTypePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"format\""));
    dataTypePart.setBody("tcx");
    body->append(dataTypePart);

    //Including file in the request
    TcxFileReader reader;
    QByteArray file = reader.toByteArray(context, ride->ride(), parent->altitudeChk->isChecked(), parent->powerChk->isChecked(), parent->heartrateChk->isChecked(), parent->cadenceChk->isChecked());
    QHttpPart filePart;
    filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"datafile\"; filename=\"sph_file.tcx\"; type=\"text/xml\""));
    filePart.setBody(file);
    body->append(filePart);

    //Sending the authenticated post request to the API
    parent->progressBar->setValue(parent->progressBar->value()+20/parent->shareSiteCount);
    QUrl url(SPH_URL + "/" + username + "/importGC");
    QNetworkRequest request;
    request.setUrl(url);
    request.setRawHeader("Authorization", "Basic " + QByteArray(QString("%1:%2").arg(username).arg(password).toLatin1()).toBase64());
    networkMgr.post(request, body);
    parent->progressBar->setValue(parent->progressBar->value()+10/parent->shareSiteCount);
}
Example #4
0
int
RideImportWizard::process()
{

    // set progress bar limits - for each file we
    // will make 5 passes over the files
    //         1. checking it is a file ane readable
    //         2. parsing it with the RideFileReader
    //         3. [optional] collect date/time information from user
    //         4. copy file into Library
    //         5. Process for CPI (not implemented yet)

    // So, therefore the progress bar runs from 0 to files*4. (since step 5 is not implemented yet)
    progressBar->setMinimum(0);
    progressBar->setMaximum(filenames.count()*4);

    // Pass one - Is it valid?
    phaseLabel->setText(tr("Step 1 of 4: Check file permissions"));
    for (int i=0; i < filenames.count(); i++) {

        // get fullpath name for processing
        QFileInfo thisfile(filenames[i]);

        if (thisfile.exists() && thisfile.isFile() && thisfile.isReadable()) {

            // is it one we understand ?
            QStringList suffixList = RideFileFactory::instance().suffixes();
            QRegExp suffixes(QString("^(%1)$").arg(suffixList.join("|")));
            suffixes.setCaseSensitivity(Qt::CaseInsensitive);

            if (suffixes.exactMatch(thisfile.suffix())) {

                // Woot. We know how to parse this baby
                tableWidget->item(i,5)->setText(tr("Queued"));

            } else {
                tableWidget->item(i,5)->setText(tr("Error - Unknown file type"));
            }

        } else {
            //  Cannot open
            tableWidget->item(i,5)->setText(tr("Error - Not a valid file"));
        }

        progressBar->setValue(progressBar->value()+1);

    }

    QApplication::processEvents();
    if (aborted) { done(0); }
    repaint();

    // Pass 2 - Read in with the relevant RideFileReader method

    phaseLabel->setText(tr("Step 2 of 4: Validating Files"));
   for (int i=0; i< filenames.count(); i++) {


        // does the status say Queued?
        if (!tableWidget->item(i,5)->text().startsWith(tr("Error"))) {

              QStringList errors;
              QFile thisfile(filenames[i]);

              tableWidget->item(i,5)->setText(tr("Parsing..."));
              tableWidget->setCurrentCell(i,5);
              QApplication::processEvents();
              if (aborted) { done(0); }
              this->repaint();

              QList<RideFile*> rides;
              RideFile *ride = RideFileFactory::instance().openRideFile(mainWindow, thisfile, errors, &rides);

              // is this an archive of files?
              if (rides.count() > 1) {

                 int here = i;

                 // remove current filename from state arrays and tableview
                 filenames.removeAt(here);
                 blanks.removeAt(here);
                 tableWidget->removeRow(here);

                 // resize dialog according to the number of rows we expect
                 int willhave = filenames.count() + rides.count();
                 resize(920 + ((willhave > 16 ? 24 : 0) +
                     (willhave > 9 && willhave < 17) ? 8 : 0),
                     118 + (willhave > 16 ? 17*20 : (willhave+1) * 20));

                 // ok so create a temporary file and add to the tableWidget
                 int counter = 0;
                 foreach(RideFile *extracted, rides) {

                     // write as a temporary file, using the original
                     // filename with "-n" appended
                     QString fulltarget = QDir::tempPath() + "/" + QFileInfo(thisfile).baseName() + QString("-%1.tcx").arg(counter+1);
                     TcxFileReader reader;
                     QFile target(fulltarget);
                     reader.writeRideFile(mainWindow, extracted, target);
                     deleteMe.append(fulltarget);
                     delete extracted;
                     
                     // now add each temporary file ...
                     filenames.insert(here, fulltarget);
                     blanks.insert(here, true); // by default editable
                     tableWidget->insertRow(here+counter);

                     QTableWidgetItem *t;

                     // Filename
                     t = new QTableWidgetItem();
                     t->setText(fulltarget);
                     t->setFlags(t->flags() & (~Qt::ItemIsEditable));
                     tableWidget->setItem(here+counter,0,t);

                     // Date
                     t = new QTableWidgetItem();
                     t->setText(tr(""));
                     t->setFlags(t->flags()  | Qt::ItemIsEditable);
                     t->setBackgroundColor(Qt::red);
                     tableWidget->setItem(here+counter,1,t);

                     // Time
                     t = new QTableWidgetItem();
                     t->setText(tr(""));
                     t->setFlags(t->flags() | Qt::ItemIsEditable);
                     tableWidget->setItem(here+counter,2,t);

                     // Duration
                     t = new QTableWidgetItem();
                     t->setText(tr(""));
                     t->setFlags(t->flags() & (~Qt::ItemIsEditable));
                     tableWidget->setItem(here+counter,3,t);

                     // Distance
                     t = new QTableWidgetItem();
                     t->setText(tr(""));
                     t->setFlags(t->flags() & (~Qt::ItemIsEditable));
                     tableWidget->setItem(here+counter,4,t);

                     // Import Status
                     t = new QTableWidgetItem();
                     t->setText(tr(""));
                     t->setFlags(t->flags() & (~Qt::ItemIsEditable));
                     tableWidget->setItem(here+counter,5,t);

                     counter++;

                     tableWidget->adjustSize();
                     QApplication::processEvents();
                 }


                 // progress bar needs to adjust...
                 progressBar->setMaximum(filenames.count()*4);

                 // then go back one and re-parse from there
                 rides.clear();
   
                 i--;
                 goto next; // buttugly I know, but count em across 100,000 lines of code

              }
        if (heartrateChk->isChecked())
            out += ", \"heartrate\"";
        out += "]}";

        QUrl url = QUrl(STRAVA_URL2 + "/upload");
        QNetworkRequest request = QNetworkRequest(url);
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

        progressBar->setValue(40);
        progressLabel->setText(tr("Upload ride... Sending"));

        networkMgr.post( request, out.toAscii());
    } else {
        QByteArray data;
        QUrl params;
        TcxFileReader reader;

        params.addQueryItem("token", token);
        params.addQueryItem("type", "tcx");
        params.addQueryItem("data", reader.toByteArray(mainWindow, ride->ride(), altitudeChk->isChecked(), powerChk->isChecked(), heartrateChk->isChecked(), cadenceChk->isChecked()));
        data = params.encodedQuery();

        QUrl url = QUrl(STRAVA_URL2 + "/upload");
        QNetworkRequest request = QNetworkRequest(url);
        request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");

        progressBar->setValue(40);
        progressLabel->setText(tr("Upload ride... Sending"));

        networkMgr.post( request, data);
    }
// Documentation is at:
// https://strava.pbworks.com/w/page/39241255/v2%20upload%20create
void
StravaUploader::requestUploadStrava()
{
    parent->progressLabel->setText(tr("Upload ride to Strava..."));
    parent->progressBar->setValue(parent->progressBar->value()+10/parent->shareSiteCount);

    QEventLoop eventLoop;
    QNetworkAccessManager networkMgr;

    int year = ride->fileName.left(4).toInt();
    int month = ride->fileName.mid(5,2).toInt();
    int day = ride->fileName.mid(8,2).toInt();
    int hour = ride->fileName.mid(11,2).toInt();
    int minute = ride->fileName.mid(14,2).toInt();;
    int second = ride->fileName.mid(17,2).toInt();;

    QDate rideDate = QDate(year, month, day);
    QTime rideTime = QTime(hour, minute, second);
    QDateTime rideDateTime = QDateTime(rideDate, rideTime);

    connect(&networkMgr, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestUploadStravaFinished(QNetworkReply*)));
    connect(&networkMgr, SIGNAL(finished(QNetworkReply *)), &eventLoop, SLOT(quit()));

    TcxFileReader reader;

    QUrl url = QUrl( "https://www.strava.com/api/v3/uploads" ); // The V3 API doc said "https://api.strava.com" but it is not working yet
    QNetworkRequest request = QNetworkRequest(url);

    //QString boundary = QString::number(qrand() * (90000000000) / (RAND_MAX + 1) + 10000000000, 16);
    QString boundary = QVariant(qrand()).toString()+QVariant(qrand()).toString()+QVariant(qrand()).toString();

    QByteArray file = reader.toByteArray(context, ride->ride(), parent->altitudeChk->isChecked(), parent->powerChk->isChecked(), parent->heartrateChk->isChecked(), parent->cadenceChk->isChecked());

    // MULTIPART *****************

    QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
    multiPart->setBoundary(boundary.toLatin1());

    QHttpPart accessTokenPart;
    accessTokenPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"access_token\""));
    accessTokenPart.setBody(token.toLatin1());

    QHttpPart activityTypePart;
    activityTypePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"activity_type\""));
    activityTypePart.setBody("ride");

    QHttpPart activityNamePart;
    activityNamePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"activity_name\""));
    activityNamePart.setBody(QString(parent->titleEdit->text()).toLatin1());

    QHttpPart dataTypePart;
    dataTypePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"data_type\""));
    dataTypePart.setBody("tcx");

    QHttpPart externalIdPart;
    externalIdPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"external_id\""));
    externalIdPart.setBody("Ride");

    QHttpPart privatePart;
    privatePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"private\""));
    privatePart.setBody("TRUE");

    QHttpPart filePart;
    filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/xml"));
    filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"file\"; filename=\"file.tcx\"; type=\"text/xml\""));
    filePart.setBody(file);


    multiPart->append(accessTokenPart);
    multiPart->append(activityTypePart);
    multiPart->append(activityNamePart);
    multiPart->append(dataTypePart);
    multiPart->append(externalIdPart);
    multiPart->append(privatePart);
    multiPart->append(filePart);

    QScopedPointer<QNetworkReply> reply( networkMgr.post(request, multiPart) );
    multiPart->setParent(reply.data());

    parent->progressBar->setValue(parent->progressBar->value()+30/parent->shareSiteCount);
    parent->progressLabel->setText(tr("Upload ride... Sending to Strava"));

    eventLoop.exec();
}