Skip to content

Commit

Permalink
add feature type to csv export (#1157)
Browse files Browse the repository at this point in the history
* add feature type to csv eport

* fix value case

* add CSVEncoder

* formatting

* update column name
  • Loading branch information
CollinBeczak authored Jan 2, 2025
1 parent dd7792b commit 4794d0d
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 14 deletions.
49 changes: 35 additions & 14 deletions app/org/maproulette/controllers/api/ChallengeController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import org.maproulette.permissions.Permission
import org.maproulette.provider.ChallengeProvider
import org.maproulette.session.{SearchParameters, SessionManager}
import org.maproulette.utils.Utils
import org.maproulette.utils.CSVEncoder
import play.api.http.HttpEntity
import play.api.libs.Files
import play.api.libs.json._
Expand Down Expand Up @@ -824,10 +825,16 @@ class ChallengeController @Inject() (
}

// Find matching geojson feature properties
var propData = ""
var propData = ""
var featureType = ""
task.geojson match {
case Some(g) =>
val taskProps = (Json.parse(g) \\ "properties")(0).as[JsObject]
val parsedFeature = Json.parse(g)
featureType = (parsedFeature \\ "geometry")(0) \ "type" match {
case JsDefined(value) => value.as[String]
case JsUndefined() => "Unknown"
}
val taskProps = (parsedFeature \\ "properties")(0).as[JsObject]
for (key <- propsToExportHeaders) {
(taskProps \ key) match {
case value: JsDefined =>
Expand Down Expand Up @@ -879,17 +886,31 @@ class ChallengeController @Inject() (
var taskLink =
s"[[hyperlink URL link=${urlPrefix}challenge/${task.parent}/task/${task.taskId}]]"

s"""${task.taskId},${taskLink},${task.parent},${challengeLink},"${task.name}","${Task.statusMap
.get(task.status)
.get}",""" +
s""""${Challenge.priorityMap.get(task.priority).get}",${mappedOn},""" +
s"""${task.completedTimeSpent.getOrElse("")},"${mapper}",""" +
s"""${Task.reviewStatusMap.get(task.reviewStatus.getOrElse(-1)).get},""" +
s""""${task.reviewedBy.getOrElse("")}",${reviewedAt},"${reviewTimeSeconds}",""" +
s""""${task.additionalReviewers.getOrElse(List()).mkString(", ")}",""" +
s""""${comments}","${task.bundleId.getOrElse("")}","${task.isBundlePrimary
.getOrElse("")}",""" +
s""""${task.tags.getOrElse("")}"${propData}${responseData}""".stripMargin
// Create a CSV row with more meaningful column names and data
val csvRow = List(
task.taskId,
taskLink,
task.parent,
challengeLink,
task.name,
featureType,
Task.statusMap.get(task.status).getOrElse(""),
Challenge.priorityMap.get(task.priority).getOrElse(""),
mappedOn,
task.completedTimeSpent.getOrElse(""),
mapper,
Task.reviewStatusMap.get(task.reviewStatus.getOrElse(-1)).get,
task.reviewedBy.getOrElse(""),
reviewedAt,
reviewTimeSeconds,
task.additionalReviewers.getOrElse(List()).mkString(", "),
comments,
task.bundleId.getOrElse(""),
task.isBundlePrimary.getOrElse(""),
task.tags.getOrElse("")
)

CSVEncoder.encodeRow(csvRow)
})

var propsToExportHeaderString = propsToExportHeaders.mkString(",")
Expand All @@ -901,7 +922,7 @@ class ChallengeController @Inject() (
ResponseHeader(OK, Map(CONTENT_DISPOSITION -> s"attachment; filename=${filename}")),
body = HttpEntity.Strict(
ByteString(
s"""TaskID,TaskLink,ChallengeID,ChallengeLink,TaskName,TaskStatus,TaskPriority,MappedOn,CompletionTime,Mapper,ReviewStatus,Reviewer,ReviewedAt,ReviewTimeSeconds,AdditionalReviewers,Comments,BundleId,IsBundlePrimary,Tags${propsToExportHeaderString}${responseHeaders}\n"""
s"""TaskID,TaskLink,ChallengeID,ChallengeLink,TaskName,GeometryType,TaskStatus,TaskPriority,MappedOn,CompletionTime,Mapper,ReviewStatus,Reviewer,ReviewedAt,ReviewTimeSeconds,AdditionalReviewers,Comments,BundleId,IsBundlePrimary,Tags${propsToExportHeaderString}${responseHeaders}\n"""
).concat(ByteString(seqString.mkString("\n"))),
Some("text/csv; header=present")
)
Expand Down
16 changes: 16 additions & 0 deletions app/org/maproulette/utils/CSVEncoder.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.maproulette.utils

object CSVEncoder {
def encodeRow(row: List[Any]): String = {
row.map(escape).mkString(",")
}

private def escape(value: Any): String = {
val strValue = value.toString
if (strValue.contains(",") || strValue.contains("\"") || strValue.contains("\n")) {
"\"" + strValue.replace("\"", "\"\"") + "\""
} else {
strValue
}
}
}

0 comments on commit 4794d0d

Please sign in to comment.