diff --git a/src/APIWebService.cpp b/src/APIWebService.cpp index 41ddb48c9..9bf03711c 100644 --- a/src/APIWebService.cpp +++ b/src/APIWebService.cpp @@ -22,6 +22,11 @@ #include "GcUpgrade.h" #include "RideDB.h" +#include "RideFile.h" +#include "CsvRideFile.h" + +#include + void APIWebService::service(HttpRequest &request, HttpResponse &response) { @@ -170,15 +175,98 @@ APIWebService::listActivity(QString athlete, QStringList paths, HttpRequest &req QFile file(filename); if (file.exists() && file.open(QFile::ReadOnly | QFile::Text)) { - // read in the whole thing - QTextStream in(&file); - // GC .JSON is stored in UTF-8 with BOM(Byte order mark) for identification - in.setCodec ("UTF-8"); - contents = in.readAll(); + // close as we will open properly below file.close(); - // write back in one hit - response.write(contents.toLocal8Bit(), true); + // what format to use ? + QString format(request.getParameter("format")); + + if (format == "") { + + // read in the whole thing + QTextStream in(&file); + // GC .JSON is stored in UTF-8 with BOM(Byte order mark) for identification + in.setCodec ("UTF-8"); + contents = in.readAll(); + file.close(); + + // write back in one hit + response.write(contents.toLocal8Bit(), true); + + } else { + + // lets go with tcx/pwx as xml, full csv (not powertap) and GC json + QStringList formats; + formats << "tcx"; // garmin training centre + formats << "csv"; // full csv list (not powertap) + formats << "json"; // gc json + formats << "pwx"; // gc json + + // unsupported format + if (!formats.contains(format)) { + response.setStatus(500); + response.write("unsupported format; we support:"); + foreach(QString fmt, formats) { + response.write(" "); + response.write(fmt.toLocal8Bit()); + } + response.write("\r\n"); + return; + } + + // lets read the file in as a ridefile + QStringList errors; + RideFile *f = RideFileFactory::instance().openRideFile(NULL, file, errors); + + // error reading (!) + if (f == NULL) { + response.setStatus(500); + foreach(QString error, errors) { + response.write(error.toLocal8Bit()); + response.write("\r\n"); + } + return; + } + + // write out to a temporary file in + // the format requested + bool success; + QTemporaryFile tempfile; // deletes file when goes out of scope + QString tempname; + if (tempfile.open()) tempname = tempfile.fileName(); + else { + response.setStatus(500); + response.write("error opening temporary file"); + return; + } + QFile out(tempname); + + if (format == "csv") { + CsvFileReader writer; + success = writer.writeRideFile(NULL, f, out, CsvFileReader::gc); + } else { + success = RideFileFactory::instance().writeRideFile(NULL, f, out, format); + } + + if (success) { + + // read in the whole thing + out.open(QFile::ReadOnly | QFile::Text); + QTextStream in(&out); + in.setCodec ("UTF-8"); + contents = in.readAll(); + out.close(); + + // write back in one hit + response.write(contents.toLocal8Bit(), true); + return; + + } else { + response.setStatus(500); + response.write("unable to write output, internal error.\n"); + return; + } + } } else { diff --git a/src/PwxRideFile.cpp b/src/PwxRideFile.cpp index caedc0154..ea89b825c 100644 --- a/src/PwxRideFile.cpp +++ b/src/PwxRideFile.cpp @@ -567,7 +567,7 @@ PwxFileReader::writeRideFile(Context *context, const RideFile *ride, QFile &file // athlete details QDomElement athlete = doc.createElement("athlete"); QDomElement name = doc.createElement("name"); - text = doc.createTextNode(context->athlete->cyclist); name.appendChild(text); + text = doc.createTextNode(context ? context->athlete->cyclist : "athlete"); name.appendChild(text); athlete.appendChild(name); double cyclistweight = ride->getTag("Weight", "0.0").toDouble(); if (cyclistweight) { diff --git a/src/RideFile.cpp b/src/RideFile.cpp index 73899831e..67b075b6c 100644 --- a/src/RideFile.cpp +++ b/src/RideFile.cpp @@ -616,9 +616,11 @@ RideFile *RideFileFactory::openRideFile(Context *context, QFile &file, // Construct the summary text used on the calendar QString calendarText; - foreach (FieldDefinition field, context->athlete->rideMetadata()->getFields()) { - if (field.diary == true && result->getTag(field.name, "") != "") { - calendarText += field.calendarText(result->getTag(field.name, "")); + if (context) { // will be null in standalone open + foreach (FieldDefinition field, context->athlete->rideMetadata()->getFields()) { + if (field.diary == true && result->getTag(field.name, "") != "") { + calendarText += field.calendarText(result->getTag(field.name, "")); + } } } result->setTag("Calendar Text", calendarText); @@ -627,7 +629,7 @@ RideFile *RideFileFactory::openRideFile(Context *context, QFile &file, result->setTag("Filename", QFileInfo(file.fileName()).fileName()); result->setTag("Device", result->deviceType()); result->setTag("File Format", result->fileFormat()); - result->setTag("Athlete", context->athlete->cyclist); + if (context) result->setTag("Athlete", context->athlete->cyclist); result->setTag("Year", result->startTime().toString("yyyy")); result->setTag("Month", result->startTime().toString("MMMM")); result->setTag("Weekday", result->startTime().toString("ddd")); @@ -656,7 +658,7 @@ RideFile *RideFileFactory::openRideFile(Context *context, QFile &file, DataProcessorFactory::instance().autoProcess(result); // calculate derived data series -- after data fixers applied above - result->recalculateDerivedSeries(); + if (context) result->recalculateDerivedSeries(); // what data is present - after processor in case 'derived' or adjusted QString flags; diff --git a/src/TcxRideFile.cpp b/src/TcxRideFile.cpp index f262c179f..2e94d9454 100644 --- a/src/TcxRideFile.cpp +++ b/src/TcxRideFile.cpp @@ -109,54 +109,57 @@ TcxFileReader::toByteArray(Context *context, const RideFile *ride, bool withAlt, QStringList worklist = QStringList(); for (int i=0; metrics[i];i++) worklist << metrics[i]; - QHash computed = RideMetric::computeMetrics(context, ride, context->athlete->zones(), context->athlete->hrZones(), worklist); + QHash computed; + if (context) { // can't do this standalone + computed = RideMetric::computeMetrics(context, ride, context->athlete->zones(), context->athlete->hrZones(), worklist); - QDomElement lap_time = doc.createElement("TotalTimeSeconds"); - text = doc.createTextNode(QString("%1").arg(computed.value("workout_time")->value(true))); - //text = doc.createTextNode(ride->dataPoints().last()->secs); - lap_time.appendChild(text); - lap.appendChild(lap_time); + QDomElement lap_time = doc.createElement("TotalTimeSeconds"); + text = doc.createTextNode(QString("%1").arg(computed.value("workout_time")->value(true))); + //text = doc.createTextNode(ride->dataPoints().last()->secs); + lap_time.appendChild(text); + lap.appendChild(lap_time); - QDomElement lap_distance = doc.createElement("DistanceMeters"); - text = doc.createTextNode(QString("%1").arg(1000*computed.value("total_distance")->value(true))); - //text = doc.createTextNode(ride->dataPoints().last()->km); - lap_distance.appendChild(text); - lap.appendChild(lap_distance); + QDomElement lap_distance = doc.createElement("DistanceMeters"); + text = doc.createTextNode(QString("%1").arg(1000*computed.value("total_distance")->value(true))); + //text = doc.createTextNode(ride->dataPoints().last()->km); + lap_distance.appendChild(text); + lap.appendChild(lap_distance); - QDomElement max_speed = doc.createElement("MaximumSpeed"); - text = doc.createTextNode(QString("%1") - .arg(computed.value("max_speed")->value(true) / 3.6)); - max_speed.appendChild(text); - lap.appendChild(max_speed); + QDomElement max_speed = doc.createElement("MaximumSpeed"); + text = doc.createTextNode(QString("%1") + .arg(computed.value("max_speed")->value(true) / 3.6)); + max_speed.appendChild(text); + lap.appendChild(max_speed); - QDomElement lap_calories = doc.createElement("Calories"); - text = doc.createTextNode(QString("%1").arg((int)computed.value("total_work")->value(true))); - lap_calories.appendChild(text); - lap.appendChild(lap_calories); + QDomElement lap_calories = doc.createElement("Calories"); + text = doc.createTextNode(QString("%1").arg((int)computed.value("total_work")->value(true))); + lap_calories.appendChild(text); + lap.appendChild(lap_calories); - QDomElement avg_heartrate = doc.createElement("AverageHeartRateBpm"); - QDomElement value = doc.createElement("Value"); - text = doc.createTextNode(QString("%1").arg((int)computed.value("average_hr")->value(true))); - value.appendChild(text); - avg_heartrate.appendChild(value); - lap.appendChild(avg_heartrate); + QDomElement avg_heartrate = doc.createElement("AverageHeartRateBpm"); + QDomElement value = doc.createElement("Value"); + text = doc.createTextNode(QString("%1").arg((int)computed.value("average_hr")->value(true))); + value.appendChild(text); + avg_heartrate.appendChild(value); + lap.appendChild(avg_heartrate); - QDomElement max_heartrate = doc.createElement("MaximumHeartRateBpm"); - value = doc.createElement("Value"); - text = doc.createTextNode(QString("%1").arg((int)computed.value("max_heartrate")->value(true))); - value.appendChild(text); - max_heartrate.appendChild(value); - lap.appendChild(max_heartrate); + QDomElement max_heartrate = doc.createElement("MaximumHeartRateBpm"); + value = doc.createElement("Value"); + text = doc.createTextNode(QString("%1").arg((int)computed.value("max_heartrate")->value(true))); + value.appendChild(text); + max_heartrate.appendChild(value); + lap.appendChild(max_heartrate); - QDomElement lap_intensity = doc.createElement("Intensity"); - text = doc.createTextNode("Active"); - lap_intensity.appendChild(text); - lap.appendChild(lap_intensity); + QDomElement lap_intensity = doc.createElement("Intensity"); + text = doc.createTextNode("Active"); + lap_intensity.appendChild(text); + lap.appendChild(lap_intensity); - QDomElement lap_triggerMethod = doc.createElement("TriggerMethod"); - text = doc.createTextNode("Manual"); - lap_triggerMethod.appendChild(text); - lap.appendChild(lap_triggerMethod); + QDomElement lap_triggerMethod = doc.createElement("TriggerMethod"); + text = doc.createTextNode("Manual"); + lap_triggerMethod.appendChild(text); + lap.appendChild(lap_triggerMethod); + } // samples // data points: timeoffset, dist, hr, spd, pwr, torq, cad, lat, lon, alt @@ -263,144 +266,145 @@ TcxFileReader::toByteArray(Context *context, const RideFile *ride, bool withAlt, } - // Activity Extensions - QDomElement extensions = doc.createElement("Extensions"); - lap.appendChild(extensions); - QDomElement lx = doc.createElement("LX"); - lx.setAttribute("xmlns", "http://www.garmin.com/xmlschemas/ActivityExtension/v2"); - extensions.appendChild(lx); + if (context) { + // Activity Extensions + QDomElement extensions = doc.createElement("Extensions"); + lap.appendChild(extensions); + QDomElement lx = doc.createElement("LX"); + lx.setAttribute("xmlns", "http://www.garmin.com/xmlschemas/ActivityExtension/v2"); + extensions.appendChild(lx); - QDomElement max_cad = doc.createElement("MaxBikeCadence"); - text = doc.createTextNode(QString("%1").arg(computed.value("max_cadence")->value(true))); - max_cad.appendChild(text); - lx.appendChild(max_cad); + QDomElement max_cad = doc.createElement("MaxBikeCadence"); + text = doc.createTextNode(QString("%1").arg(computed.value("max_cadence")->value(true))); + max_cad.appendChild(text); + lx.appendChild(max_cad); - lx = doc.createElement("LX"); - lx.setAttribute("xmlns", "http://www.garmin.com/xmlschemas/ActivityExtension/v2"); - extensions.appendChild(lx); + lx = doc.createElement("LX"); + lx.setAttribute("xmlns", "http://www.garmin.com/xmlschemas/ActivityExtension/v2"); + extensions.appendChild(lx); - QDomElement avg_speed = doc.createElement("AvgSpeed"); - text = doc.createTextNode(QString("%1") - .arg(computed.value("average_speed")->value(true) / 3.6)); - avg_speed.appendChild(text); - lx.appendChild(avg_speed); + QDomElement avg_speed = doc.createElement("AvgSpeed"); + text = doc.createTextNode(QString("%1") + .arg(computed.value("average_speed")->value(true) / 3.6)); + avg_speed.appendChild(text); + lx.appendChild(avg_speed); - lx = doc.createElement("LX"); - lx.setAttribute("xmlns", "http://www.garmin.com/xmlschemas/ActivityExtension/v2"); - extensions.appendChild(lx); + lx = doc.createElement("LX"); + lx.setAttribute("xmlns", "http://www.garmin.com/xmlschemas/ActivityExtension/v2"); + extensions.appendChild(lx); - QDomElement avg_power = doc.createElement("AvgWatts"); - text = doc.createTextNode(QString("%1").arg((int)computed.value("average_power")->value(true))); - avg_power.appendChild(text); - lx.appendChild(avg_power); + QDomElement avg_power = doc.createElement("AvgWatts"); + text = doc.createTextNode(QString("%1").arg((int)computed.value("average_power")->value(true))); + avg_power.appendChild(text); + lx.appendChild(avg_power); - lx = doc.createElement("LX"); - lx.setAttribute("xmlns", "http://www.garmin.com/xmlschemas/ActivityExtension/v2"); - extensions.appendChild(lx); + lx = doc.createElement("LX"); + lx.setAttribute("xmlns", "http://www.garmin.com/xmlschemas/ActivityExtension/v2"); + extensions.appendChild(lx); - QDomElement max_power = doc.createElement("MaxWatts"); - text = doc.createTextNode(QString("%1").arg((int)computed.value("max_power")->value(true))); - max_power.appendChild(text); - lx.appendChild(max_power); + QDomElement max_power = doc.createElement("MaxWatts"); + text = doc.createTextNode(QString("%1").arg((int)computed.value("max_power")->value(true))); + max_power.appendChild(text); + lx.appendChild(max_power); - // Creator - Device - QDomElement creator = doc.createElement("Creator"); - creator.setAttribute("xsi:type", "Device_t"); - activity.appendChild(creator); + // Creator - Device + QDomElement creator = doc.createElement("Creator"); + creator.setAttribute("xsi:type", "Device_t"); + activity.appendChild(creator); - QDomElement creator_name = doc.createElement("Name"); - if (ride->deviceType() != "") - text = doc.createTextNode(ride->deviceType()); - else - text = doc.createTextNode("Unknown"); - creator_name.appendChild(text); - creator.appendChild(creator_name); + QDomElement creator_name = doc.createElement("Name"); + if (ride->deviceType() != "") + text = doc.createTextNode(ride->deviceType()); + else + text = doc.createTextNode("Unknown"); + creator_name.appendChild(text); + creator.appendChild(creator_name); - QDomElement creator_unitId = doc.createElement("UnitId"); - text = doc.createTextNode("0"); - creator_unitId.appendChild(text); - creator.appendChild(creator_unitId); + QDomElement creator_unitId = doc.createElement("UnitId"); + text = doc.createTextNode("0"); + creator_unitId.appendChild(text); + creator.appendChild(creator_unitId); - QDomElement creator_productId = doc.createElement("ProductID"); - text = doc.createTextNode("0"); - creator_productId.appendChild(text); - creator.appendChild(creator_productId); + QDomElement creator_productId = doc.createElement("ProductID"); + text = doc.createTextNode("0"); + creator_productId.appendChild(text); + creator.appendChild(creator_productId); - QDomElement creator_version = doc.createElement("Version"); - creator.appendChild(creator_version); + QDomElement creator_version = doc.createElement("Version"); + creator.appendChild(creator_version); - QDomElement creator_version_version_major = doc.createElement("VersionMajor"); - text = doc.createTextNode("3"); - creator_version_version_major.appendChild(text); - creator_version.appendChild(creator_version_version_major); + QDomElement creator_version_version_major = doc.createElement("VersionMajor"); + text = doc.createTextNode("3"); + creator_version_version_major.appendChild(text); + creator_version.appendChild(creator_version_version_major); - QDomElement creator_version_version_minor = doc.createElement("VersionMinor"); - text = doc.createTextNode("0"); - creator_version_version_minor.appendChild(text); - creator_version.appendChild(creator_version_version_minor); + QDomElement creator_version_version_minor = doc.createElement("VersionMinor"); + text = doc.createTextNode("0"); + creator_version_version_minor.appendChild(text); + creator_version.appendChild(creator_version_version_minor); - QDomElement creator_version_build_major = doc.createElement("BuildMajor"); - text = doc.createTextNode("0"); - creator_version_build_major.appendChild(text); - creator_version.appendChild(creator_version_build_major); + QDomElement creator_version_build_major = doc.createElement("BuildMajor"); + text = doc.createTextNode("0"); + creator_version_build_major.appendChild(text); + creator_version.appendChild(creator_version_build_major); - QDomElement creator_version_build_minor = doc.createElement("BuildMinor"); - text = doc.createTextNode("0"); - creator_version_build_minor.appendChild(text); - creator_version.appendChild(creator_version_build_minor); + QDomElement creator_version_build_minor = doc.createElement("BuildMinor"); + text = doc.createTextNode("0"); + creator_version_build_minor.appendChild(text); + creator_version.appendChild(creator_version_build_minor); - // Author - Application - QDomElement author = doc.createElement("Author"); - author.setAttribute("xsi:type", "Application_t"); - tcx.appendChild(author); + // Author - Application + QDomElement author = doc.createElement("Author"); + author.setAttribute("xsi:type", "Application_t"); + tcx.appendChild(author); - QDomElement author_name = doc.createElement("Name"); - text = doc.createTextNode("GoldenCheetah"); - author_name.appendChild(text); - author.appendChild(author_name); + QDomElement author_name = doc.createElement("Name"); + text = doc.createTextNode("GoldenCheetah"); + author_name.appendChild(text); + author.appendChild(author_name); - QDomElement author_build = doc.createElement("Build"); - author.appendChild(author_build); + QDomElement author_build = doc.createElement("Build"); + author.appendChild(author_build); - QDomElement author_version = doc.createElement("Version"); - author_build.appendChild(author_version); + QDomElement author_version = doc.createElement("Version"); + author_build.appendChild(author_version); - QDomElement author_version_version_major = doc.createElement("VersionMajor"); - text = doc.createTextNode("3"); - author_version_version_major.appendChild(text); - author_version.appendChild(author_version_version_major); + QDomElement author_version_version_major = doc.createElement("VersionMajor"); + text = doc.createTextNode("3"); + author_version_version_major.appendChild(text); + author_version.appendChild(author_version_version_major); - QDomElement author_version_version_minor = doc.createElement("VersionMinor"); - text = doc.createTextNode("0"); - author_version_version_minor.appendChild(text); - author_version.appendChild(author_version_version_minor); + QDomElement author_version_version_minor = doc.createElement("VersionMinor"); + text = doc.createTextNode("0"); + author_version_version_minor.appendChild(text); + author_version.appendChild(author_version_version_minor); - QDomElement author_version_build_major = doc.createElement("BuildMajor"); - text = doc.createTextNode("0"); - author_version_build_major.appendChild(text); - author_version.appendChild(author_version_build_major); + QDomElement author_version_build_major = doc.createElement("BuildMajor"); + text = doc.createTextNode("0"); + author_version_build_major.appendChild(text); + author_version.appendChild(author_version_build_major); - QDomElement author_version_build_minor = doc.createElement("BuildMinor"); - text = doc.createTextNode("0"); - author_version_build_minor.appendChild(text); - author_version.appendChild(author_version_build_minor); + QDomElement author_version_build_minor = doc.createElement("BuildMinor"); + text = doc.createTextNode("0"); + author_version_build_minor.appendChild(text); + author_version.appendChild(author_version_build_minor); - QDomElement author_type = doc.createElement("Type"); - text = doc.createTextNode("Beta"); // was GC_VERSION but should be Interna | Alpha | Beta | Release - author_type.appendChild(text); - author_build.appendChild(author_type); + QDomElement author_type = doc.createElement("Type"); + text = doc.createTextNode("Beta"); // was GC_VERSION but should be Interna | Alpha | Beta | Release + author_type.appendChild(text); + author_build.appendChild(author_type); - QDomElement author_lang = doc.createElement("LangID"); - QVariant lang = appsettings->value(NULL, GC_LANG, QLocale::system().name()); - text = doc.createTextNode(lang.toString()); - author_lang.appendChild(text); - author.appendChild(author_lang); - - QDomElement author_part_number = doc.createElement("PartNumber"); - text = doc.createTextNode("000-00000-00"); - author_part_number.appendChild(text); - author.appendChild(author_part_number); + QDomElement author_lang = doc.createElement("LangID"); + QVariant lang = appsettings->value(NULL, GC_LANG, QLocale::system().name()); + text = doc.createTextNode(lang.toString()); + author_lang.appendChild(text); + author.appendChild(author_lang); + QDomElement author_part_number = doc.createElement("PartNumber"); + text = doc.createTextNode("000-00000-00"); + author_part_number.appendChild(text); + author.appendChild(author_part_number); + } return doc.toByteArray(4); }