diff --git a/app/controllers/TaskController.scala b/app/controllers/TaskController.scala index 061a7088e5..1cc27ed820 100644 --- a/app/controllers/TaskController.scala +++ b/app/controllers/TaskController.scala @@ -10,11 +10,12 @@ import com.vividsolutions.jts.geom._ import controllers.headers.ProvidesHeader import controllers.helper.ControllerUtils.sendSciStarterContributions import formats.json.TaskSubmissionFormats._ +import formats.json.PanoHistoryFormats._ import models.amt.AMTAssignmentTable import models.audit.AuditTaskInteractionTable.secondsAudited import models.audit._ import models.daos.slick.DBTableDefinitions.{DBUser, UserTable} -import models.gsv.{GSVData, GSVDataTable, GSVLink, GSVLinkTable} +import models.gsv.{GSVData, GSVDataTable, GSVLink, GSVLinkTable, PanoHistory, PanoHistoryTable} import models.label._ import models.mission.{Mission, MissionTable} import models.region._ @@ -221,7 +222,6 @@ class TaskController @Inject() (implicit val env: Environment[User, SessionAuthe val streetEdgeId: Int = data.auditTask.streetEdgeId val missionId: Int = data.missionProgress.missionId val currTime: Timestamp = new Timestamp(data.timestamp) - if (data.auditTask.auditTaskId.isDefined) { val priorityBefore: StreetEdgePriority = streetPrioritiesFromIds(List(streetEdgeId)).head userOption match { @@ -355,11 +355,11 @@ class TaskController @Inject() (implicit val env: Environment[User, SessionAuthe // Insert new entry to gsv_data table, or update the last_viewed column if we've already recorded it. if (GSVDataTable.panoramaExists(pano.gsvPanoramaId)) { GSVDataTable.updateFromExplore(pano.gsvPanoramaId, pano.lat, pano.lng, pano.cameraHeading, - pano.cameraPitch, expired = false, currTime) + pano.cameraPitch, expired = false, currTime, Some(currTime)) } else { val gsvData: GSVData = GSVData(pano.gsvPanoramaId, pano.width, pano.height, pano.tileWidth, pano.tileHeight, pano.captureDate, pano.copyright, pano.lat, pano.lng, pano.cameraHeading, pano.cameraPitch, expired = false, - currTime) + currTime, Some(currTime)) GSVDataTable.save(gsvData) } for (link <- pano.links) { @@ -368,6 +368,9 @@ class TaskController @Inject() (implicit val env: Environment[User, SessionAuthe GSVLinkTable.save(gsvLink) } } + + // Save the history of the panoramas at this location. + pano.history.foreach { h => PanoHistoryTable.save(PanoHistory(h.panoId, h.date, pano.gsvPanoramaId)) } } // Check for streets in the user's neighborhood that have been audited by other users while they were auditing. diff --git a/app/controllers/ValidationTaskController.scala b/app/controllers/ValidationTaskController.scala index 628d8d9324..3e9492190c 100644 --- a/app/controllers/ValidationTaskController.scala +++ b/app/controllers/ValidationTaskController.scala @@ -9,12 +9,14 @@ import controllers.headers.ProvidesHeader import controllers.helper.ControllerUtils.{isAdmin, sendSciStarterContributions} import controllers.helper.ValidateHelper.{AdminValidateParams, getLabelTypeIdToValidate} import formats.json.ValidationTaskSubmissionFormats._ +import formats.json.PanoHistoryFormats._ import models.amt.AMTAssignmentTable import models.label._ import models.label.LabelTable.{AdminValidationData, LabelValidationMetadata} import models.mission.{Mission, MissionTable} import models.user.{User, UserStatTable} import models.validation._ +import models.gsv.{GSVDataTable, PanoHistory, PanoHistoryTable} import play.api.libs.json._ import play.api.{Logger, Play} import play.api.mvc._ @@ -90,6 +92,15 @@ class ValidationTaskController @Inject() (implicit val env: Environment[User, Se UserStatTable.updateAccuracy(usersValidated) } + // Adding the new panorama information to the pano_history table. + data.panoHistories.foreach { panoHistory => + // First, update the panorama that shows up currently for the current location in the GSVDataTable. + GSVDataTable.updatePanoHistorySaved(panoHistory.currPanoId, Some(new Timestamp(panoHistory.panoHistorySaved))) + + // Add all of the panoramas at the current location. + panoHistory.history.foreach { h => PanoHistoryTable.save(PanoHistory(h.panoId, h.date, panoHistory.currPanoId)) } + } + // We aren't always submitting mission progress, so check if data.missionProgress exists. val returnValue: ValidationTaskPostReturnValue = data.missionProgress match { case Some(_) => diff --git a/app/formats/json/PanoHistoryFormats.scala b/app/formats/json/PanoHistoryFormats.scala new file mode 100644 index 0000000000..f07ac32ebe --- /dev/null +++ b/app/formats/json/PanoHistoryFormats.scala @@ -0,0 +1,20 @@ +package formats.json + +import play.api.libs.json.{JsPath, Reads} +import play.api.libs.functional.syntax._ + +object PanoHistoryFormats { + case class PanoDate(panoId: String, date: String) + case class PanoHistorySubmission(currPanoId: String, history: Seq[PanoDate], panoHistorySaved: Long) + + implicit val PanoDateReads: Reads[PanoDate] = ( + (JsPath \ "pano_id").read[String] and + (JsPath \ "date").read[String] + )(PanoDate.apply _) + + implicit val PanoHistorySubmissionReads: Reads[PanoHistorySubmission] = ( + (JsPath \ "curr_pano_id").read[String] and + (JsPath \ "history").read[Seq[PanoDate]] and + (JsPath \ "pano_history_saved").read[Long] + )(PanoHistorySubmission.apply _) +} diff --git a/app/formats/json/TaskSubmissionFormats.scala b/app/formats/json/TaskSubmissionFormats.scala index d215d6101a..52b30b9331 100644 --- a/app/formats/json/TaskSubmissionFormats.scala +++ b/app/formats/json/TaskSubmissionFormats.scala @@ -3,8 +3,8 @@ package formats.json import play.api.libs.json.{JsPath, Reads} import com.vividsolutions.jts.geom._ -import scala.collection.immutable.Seq import play.api.libs.functional.syntax._ +import formats.json.PanoHistoryFormats._ object TaskSubmissionFormats { case class EnvironmentSubmission(browser: Option[String], browserVersion: Option[String], browserWidth: Option[Int], browserHeight: Option[Int], availWidth: Option[Int], availHeight: Option[Int], screenWidth: Option[Int], screenHeight: Option[Int], operatingSystem: Option[String], language: String, cssZoom: Int) @@ -14,7 +14,7 @@ object TaskSubmissionFormats { case class TaskSubmission(streetEdgeId: Int, taskStart: Long, auditTaskId: Option[Int], completed: Option[Boolean], currentLat: Float, currentLng: Float, startPointReversed: Boolean, currentMissionStart: Option[Point], lastPriorityUpdateTime: Long, requestUpdatedStreetPriority: Boolean) case class IncompleteTaskSubmission(issueDescription: String, lat: Float, lng: Float) case class GSVLinkSubmission(targetGsvPanoramaId: String, yawDeg: Double, description: String) - case class GSVPanoramaSubmission(gsvPanoramaId: String, captureDate: String, width: Option[Int], height: Option[Int], tileWidth: Option[Int], tileHeight: Option[Int], lat: Option[Float], lng: Option[Float], cameraHeading: Option[Float], cameraPitch: Option[Float], links: Seq[GSVLinkSubmission], copyright: String) + case class GSVPanoramaSubmission(gsvPanoramaId: String, captureDate: String, width: Option[Int], height: Option[Int], tileWidth: Option[Int], tileHeight: Option[Int], lat: Option[Float], lng: Option[Float], cameraHeading: Option[Float], cameraPitch: Option[Float], links: Seq[GSVLinkSubmission], copyright: String, history: Seq[PanoDate]) case class AuditMissionProgress(missionId: Int, distanceProgress: Option[Float], completed: Boolean, auditTaskId: Option[Int], skipped: Boolean) case class AuditTaskSubmission(missionProgress: AuditMissionProgress, auditTask: TaskSubmission, labels: Seq[LabelSubmission], interactions: Seq[InteractionSubmission], environment: EnvironmentSubmission, incomplete: Option[IncompleteTaskSubmission], gsvPanoramas: Seq[GSVPanoramaSubmission], amtAssignmentId: Option[Int], userRouteId: Option[Int], timestamp: Long) case class AMTAssignmentCompletionSubmission(assignmentId: Int, completed: Option[Boolean]) @@ -116,7 +116,8 @@ object TaskSubmissionFormats { (JsPath \ "camera_heading").readNullable[Float] and (JsPath \ "camera_pitch").readNullable[Float] and (JsPath \ "links").read[Seq[GSVLinkSubmission]] and - (JsPath \ "copyright").read[String] + (JsPath \ "copyright").read[String] and + (JsPath \ "history").read[Seq[PanoDate]] )(GSVPanoramaSubmission.apply _) implicit val auditMissionProgressReads: Reads[AuditMissionProgress] = ( diff --git a/app/formats/json/ValidationTaskSubmissionFormats.scala b/app/formats/json/ValidationTaskSubmissionFormats.scala index b3e9006d9a..e62166acbe 100644 --- a/app/formats/json/ValidationTaskSubmissionFormats.scala +++ b/app/formats/json/ValidationTaskSubmissionFormats.scala @@ -1,10 +1,9 @@ package formats.json import controllers.helper.ValidateHelper.AdminValidateParams -import java.sql.Timestamp -import play.api.libs.json.{JsBoolean, JsPath, Reads} -import scala.collection.immutable.Seq +import play.api.libs.json.{JsPath, Reads} import play.api.libs.functional.syntax._ +import formats.json.PanoHistoryFormats._ object ValidationTaskSubmissionFormats { case class EnvironmentSubmission(missionId: Option[Int], browser: Option[String], browserVersion: Option[String], browserWidth: Option[Int], browserHeight: Option[Int], availWidth: Option[Int], availHeight: Option[Int], screenWidth: Option[Int], screenHeight: Option[Int], operatingSystem: Option[String], language: String, cssZoom: Int) @@ -12,7 +11,7 @@ object ValidationTaskSubmissionFormats { case class LabelValidationSubmission(labelId: Int, missionId: Int, validationResult: Int, oldSeverity: Option[Int], newSeverity: Option[Int], oldTags: List[String], newTags: List[String], canvasX: Option[Int], canvasY: Option[Int], heading: Float, pitch: Float, zoom: Float, canvasHeight: Int, canvasWidth: Int, startTimestamp: Long, endTimestamp: Long, source: String, undone: Option[Boolean]) case class SkipLabelSubmission(labels: Seq[LabelValidationSubmission], adminParams: AdminValidateParams) case class ValidationMissionProgress(missionId: Int, missionType: String, labelsProgress: Int, labelTypeId: Int, completed: Boolean, skipped: Boolean) - case class ValidationTaskSubmission(interactions: Seq[InteractionSubmission], environment: EnvironmentSubmission, validations: Seq[LabelValidationSubmission], missionProgress: Option[ValidationMissionProgress], adminParams: AdminValidateParams, timestamp: Long) + case class ValidationTaskSubmission(interactions: Seq[InteractionSubmission], environment: EnvironmentSubmission, validations: Seq[LabelValidationSubmission], missionProgress: Option[ValidationMissionProgress], adminParams: AdminValidateParams, panoHistories: Seq[PanoHistorySubmission], timestamp: Long) case class LabelMapValidationSubmission(labelId: Int, labelType: String, validationResult: Int, oldSeverity: Option[Int], newSeverity: Option[Int], oldTags: List[String], newTags: List[String], canvasX: Option[Int], canvasY: Option[Int], heading: Float, pitch: Float, zoom: Float, canvasHeight: Int, canvasWidth: Int, startTimestamp: Long, endTimestamp: Long, source: String) implicit val environmentSubmissionReads: Reads[EnvironmentSubmission] = ( @@ -87,6 +86,7 @@ object ValidationTaskSubmissionFormats { (JsPath \ "validations").read[Seq[LabelValidationSubmission]] and (JsPath \ "mission_progress").readNullable[ValidationMissionProgress] and (JsPath \ "admin_params").read[AdminValidateParams] and + (JsPath \ "pano_histories").read[Seq[PanoHistorySubmission]] and (JsPath \ "timestamp").read[Long] )(ValidationTaskSubmission.apply _) diff --git a/app/models/gsv/GSVDataTable.scala b/app/models/gsv/GSVDataTable.scala index 1382f255be..4e95dd9445 100644 --- a/app/models/gsv/GSVDataTable.scala +++ b/app/models/gsv/GSVDataTable.scala @@ -8,7 +8,7 @@ import play.api.Play.current case class GSVData(gsvPanoramaId: String, width: Option[Int], height: Option[Int], tileWidth: Option[Int], tileHeight: Option[Int], captureDate: String, copyright: String, lat: Option[Float], lng: Option[Float], cameraHeading: Option[Float], cameraPitch: Option[Float], expired: Boolean, - lastViewed: java.sql.Timestamp) + lastViewed: java.sql.Timestamp, panoHistorySaved: Option[java.sql.Timestamp]) case class GSVDataSlim(gsvPanoramaId: String, width: Option[Int], height: Option[Int], lat: Option[Float], lng: Option[Float], cameraHeading: Option[Float], cameraPitch: Option[Float]) @@ -26,10 +26,11 @@ class GSVDataTable(tag: Tag) extends Table[GSVData](tag, "gsv_data") { def cameraHeading = column[Option[Float]]("camera_heading", O.Nullable) def cameraPitch = column[Option[Float]]("camera_pitch", O.Nullable) def expired = column[Boolean]("expired", O.NotNull) - def lastViewed = column[java.sql.Timestamp]("last_viewed", O.Nullable) + def lastViewed = column[java.sql.Timestamp]("last_viewed", O.NotNull) + def panoHistorySaved = column[Option[java.sql.Timestamp]]("pano_history_saved", O.Nullable) def * = (gsvPanoramaId, width, height, tileWidth, tileHeight, captureDate, copyright, lat, lng, - cameraHeading, cameraPitch, expired, lastViewed) <> + cameraHeading, cameraPitch, expired, lastViewed, panoHistorySaved) <> ((GSVData.apply _).tupled, GSVData.unapply) } @@ -76,10 +77,10 @@ object GSVDataTable { /** * Updates the data from the GSV API for a pano that sometimes changes. */ - def updateFromExplore(gsvPanoramaId: String, lat: Option[Float], lng: Option[Float], heading: Option[Float], pitch: Option[Float], expired: Boolean, lastViewed: java.sql.Timestamp): Int = db.withSession { implicit session => + def updateFromExplore(gsvPanoramaId: String, lat: Option[Float], lng: Option[Float], heading: Option[Float], pitch: Option[Float], expired: Boolean, lastViewed: java.sql.Timestamp, panoHistorySaved: Option[java.sql.Timestamp]): Int = db.withSession { implicit session => val q = for { pano <- gsvDataRecords if pano.gsvPanoramaId === gsvPanoramaId } - yield (pano.lat, pano.lng, pano.cameraHeading, pano.cameraPitch, pano.expired, pano.lastViewed) - q.update((lat, lng, heading, pitch, expired, lastViewed)) + yield (pano.lat, pano.lng, pano.cameraHeading, pano.cameraPitch, pano.expired, pano.lastViewed, pano.panoHistorySaved) + q.update((lat, lng, heading, pitch, expired, lastViewed, panoHistorySaved)) } /** @@ -92,6 +93,17 @@ object GSVDataTable { gsvDataRecords.filter(_.gsvPanoramaId === panoramaId).list.nonEmpty } + /** + * This method updates a given panorama's panoHistorySaved field + * + * @param panoramaId Google Street View panorama Id + * @param panoHistorySaved Timestamp that this panorama was last viewed by any user + * @return + */ + def updatePanoHistorySaved(panoramaId: String, panoHistorySaved: Option[java.sql.Timestamp]): Int = db.withSession { implicit session => + gsvDataRecords.filter(_.gsvPanoramaId === panoramaId).map(_.panoHistorySaved).update(panoHistorySaved) + } + def save(data: GSVData): String = db.withSession { implicit session => gsvDataRecords += data data.gsvPanoramaId diff --git a/app/models/gsv/PanoHistoryTable.scala b/app/models/gsv/PanoHistoryTable.scala new file mode 100644 index 0000000000..8911ac7ffb --- /dev/null +++ b/app/models/gsv/PanoHistoryTable.scala @@ -0,0 +1,33 @@ +package models.gsv + +import models.utils.MyPostgresDriver.simple._ +import play.api.Play.current +import scala.slick.lifted.ForeignKeyQuery + +case class PanoHistory(panoId: String, captureDate: String, locationCurrPanoId: String) + +class PanoHistoryTable(tag: Tag) extends Table[PanoHistory](tag, "pano_history") { + def panoId: Column[String] = column[String]("pano_id", O.NotNull) + def captureDate: Column[String] = column[String]("capture_date", O.NotNull) + def locationCurrPanoId: Column[String] = column[String]("location_curr_pano_id", O.NotNull) + + def * = (panoId, captureDate, locationCurrPanoId) <> ((PanoHistory.apply _).tupled, PanoHistory.unapply) + + def locationCurrentPano: ForeignKeyQuery[GSVDataTable, GSVData] = foreignKey("pano_history_gsv_panorama_id_fkey", locationCurrPanoId, TableQuery[GSVDataTable])(_.gsvPanoramaId) +} + +object PanoHistoryTable { + val db = play.api.db.slick.DB + val panoHistoryTable = TableQuery[PanoHistoryTable] + + /** + * Save a pano history object to the PanoHistory table if it isn't already in the table. + */ + def save(history: PanoHistory): Int = db.withSession { implicit session => + if (panoHistoryTable.filter(h => h.panoId === history.panoId && h.locationCurrPanoId === history.locationCurrPanoId).list.isEmpty) { + panoHistoryTable += history + } else { + 0 + } + } +} diff --git a/conf/evolutions/default/226.sql b/conf/evolutions/default/226.sql new file mode 100644 index 0000000000..2f44afd6a9 --- /dev/null +++ b/conf/evolutions/default/226.sql @@ -0,0 +1,15 @@ +# --- !Ups +ALTER TABLE gsv_data ADD COLUMN pano_history_saved TIMESTAMPTZ; + +CREATE TABLE pano_history ( + pano_id TEXT NOT NULL, + capture_date TEXT NOT NULL, + location_curr_pano_id TEXT NOT NULL, + FOREIGN KEY (location_curr_pano_id) REFERENCES gsv_data(gsv_panorama_id) +); +ALTER TABLE pano_history OWNER TO sidewalk; -- This just helps us give table correct permissions on prod server. + +# --- !Downs +DROP TABLE pano_history; + +ALTER TABLE gsv_data DROP COLUMN pano_history_saved; diff --git a/public/javascripts/SVLabel/src/SVLabel/data/Form.js b/public/javascripts/SVLabel/src/SVLabel/data/Form.js index b9ef474fcd..c88c82fa62 100644 --- a/public/javascripts/SVLabel/src/SVLabel/data/Form.js +++ b/public/javascripts/SVLabel/src/SVLabel/data/Form.js @@ -25,13 +25,23 @@ function Form (labelContainer, missionModel, missionContainer, navigationModel, self.submitData(true); }); + this.convertPanoHistoryFormat = function (prevPanos) { + var history = []; + for (let i = 0; i < prevPanos.length; i++) { + history.push({ + pano_id: prevPanos[i].pano, + date: moment(prevPanos[i].Gw).format('YYYY-MM') + }); + } + return history; + } + /** * This method gathers all the data needed for submission. * @returns {{}} */ this.compileSubmissionData = function (task) { var data = { timestamp: new Date().getTime() }; - data.amt_assignment_id = svl.amtAssignmentId; data.user_route_id = svl.userRouteId; @@ -148,8 +158,10 @@ function Form (labelContainer, missionModel, missionContainer, navigationModel, }); } } + + var panoId = ("location" in panoData && "pano" in panoData.location) ? panoData.location.pano : ""; temp = { - panorama_id: ("location" in panoData && "pano" in panoData.location) ? panoData.location.pano : "", + panorama_id: panoId, capture_date: "imageDate" in panoData ? panoData.imageDate : "", width: panoData.tiles.worldSize.width, height: panoData.tiles.worldSize.height, @@ -160,12 +172,17 @@ function Form (labelContainer, missionModel, missionContainer, navigationModel, camera_heading: panoData.tiles.originHeading, camera_pitch: -panoData.tiles.originPitch, // camera_pitch is negative origin_pitch. links: links, - copyright: "copyright" in panoData ? panoData.copyright : "" + copyright: "copyright" in panoData ? panoData.copyright : "", + history: [] }; + + if (panoData.time !== undefined && panoId !== "") { + temp.history = this.convertPanoHistoryFormat(panoData.time); + } + data.gsv_panoramas.push(temp); panoramas[i].setProperty("submitted", true); } - return data; }; diff --git a/public/javascripts/SVLabel/src/SVLabel/mission/Mission.js b/public/javascripts/SVLabel/src/SVLabel/mission/Mission.js index fdfec9014b..c35802b8b8 100644 --- a/public/javascripts/SVLabel/src/SVLabel/mission/Mission.js +++ b/public/javascripts/SVLabel/src/SVLabel/mission/Mission.js @@ -21,7 +21,7 @@ function Mission(parameters) { }, _tasksForTheMission = [], labelCountsAtCompletion; - + function _init(parameters) { if ("missionId" in parameters) setProperty("missionId", parameters.missionId); if ("missionType" in parameters) setProperty("missionType", parameters.missionType); diff --git a/public/javascripts/SVLabel/src/SVLabel/navigation/MapService.js b/public/javascripts/SVLabel/src/SVLabel/navigation/MapService.js index 376bdde272..30c50e24a8 100644 --- a/public/javascripts/SVLabel/src/SVLabel/navigation/MapService.js +++ b/public/javascripts/SVLabel/src/SVLabel/navigation/MapService.js @@ -31,7 +31,7 @@ function MapService (canvas, neighborhoodModel, uiMap, params) { isInternetExplore: undefined }, status = { - currentPanoId: undefined, + currPanoId: undefined, disablePanning: false, disableWalking : false, hideNonavailablePanoLinks : false, @@ -1111,10 +1111,10 @@ function MapService (canvas, neighborhoodModel, uiMap, params) { function updateCanvas() { _canvas.clear(); - if (status.currentPanoId !== getPanoId()) { + if (status.currPanoId !== getPanoId()) { _canvas.setOnlyLabelsOnPanoAsVisible(getPanoId()); } - status.currentPanoId = getPanoId(); + status.currPanoId = getPanoId(); _canvas.render(); } @@ -1354,7 +1354,6 @@ function MapService (canvas, neighborhoodModel, uiMap, params) { // If there is no imagery here that we haven't already been stuck in, either try further down the street, // try with a larger radius, or just jump to a new street if all else fails. if (status !== GSV_OK || _stuckPanos.includes(streetViewPanoData.location.pano)) { - // If there is room to move forward then try again, recursively calling getPanorama with this callback. if (turf.length(remainder) > 0) { // Save the current pano ID as one that doesn't work. diff --git a/public/javascripts/SVLabel/src/SVLabel/panorama/Panorama.js b/public/javascripts/SVLabel/src/SVLabel/panorama/Panorama.js index 6b099a8e25..7932ce71c3 100644 --- a/public/javascripts/SVLabel/src/SVLabel/panorama/Panorama.js +++ b/public/javascripts/SVLabel/src/SVLabel/panorama/Panorama.js @@ -19,4 +19,4 @@ function Panorama(data) { self.getProperty = getProperty; self.setProperty = setProperty; return self; -} \ No newline at end of file +} diff --git a/public/javascripts/SVValidate/src/data/Form.js b/public/javascripts/SVValidate/src/data/Form.js index 0448d2b4bb..f7f420acea 100644 --- a/public/javascripts/SVValidate/src/data/Form.js +++ b/public/javascripts/SVValidate/src/data/Form.js @@ -60,6 +60,11 @@ function Form(url, beaconUrl) { }; data.interactions = svv.tracker.getActions(); + data.pano_histories = []; + if (svv.panoramaContainer) { + data.pano_histories = svv.panoramaContainer.getPanoHistories(); + svv.panoramaContainer.clearPanoHistories(); + } svv.tracker.refresh(); return data; } diff --git a/public/javascripts/SVValidate/src/mission/MissionContainer.js b/public/javascripts/SVValidate/src/mission/MissionContainer.js index 6b790db6fb..d8fa28ef64 100644 --- a/public/javascripts/SVValidate/src/mission/MissionContainer.js +++ b/public/javascripts/SVValidate/src/mission/MissionContainer.js @@ -9,7 +9,7 @@ function MissionContainer () { let _completedMissions = []; /** - * Adds a mission to in progress or list of completed missions + * Adds a mission to in progress or list of completed missions. * @param mission * @private */ diff --git a/public/javascripts/SVValidate/src/panorama/Panorama.js b/public/javascripts/SVValidate/src/panorama/Panorama.js index 812d884841..be45350c0d 100644 --- a/public/javascripts/SVValidate/src/panorama/Panorama.js +++ b/public/javascripts/SVValidate/src/panorama/Panorama.js @@ -193,10 +193,17 @@ function Panorama (label) { svv.tracker.push('PanoId_Changed'); } } - if (!isMobile()) { - streetViewService.getPanorama({pano: panorama.getPano()}, - function (data, status) { - if (status === google.maps.StreetViewStatus.OK) { + streetViewService.getPanorama({ pano: panorama.getPano() }, + function (data, status) { + if (status === google.maps.StreetViewStatus.OK) { + var panoHist = {}; + panoHist.curr_pano_id = panorama.getPano(); + panoHist.pano_history_saved = new Date().getTime(); + panoHist.history = data.time.map((oldPano) => { + return { pano_id: oldPano.pano, date: moment(oldPano.Gw).format('YYYY-MM') }; + }); + svv.panoramaContainer.addPanoHistory(panoHist); + if (!isMobile()) { document.getElementById("svv-panorama-date").innerText = moment(data.imageDate).format('MMM YYYY'); // Remove Keyboard shortcuts link and make Terms of Use & Report a problem links clickable. // https://github.com/ProjectSidewalk/SidewalkWebpage/issues/2546 @@ -213,12 +220,13 @@ function Panorama (label) { }, 100); } - } else { - console.error("Error retrieving Panoramas: " + status); - svv.tracker.push("PanoId_NotFound", {'TargetPanoId': panoramaId}); } - }); - } + } else { + console.error("Error retrieving Panoramas: " + status); + svv.tracker.push("PanoId_NotFound", {'TargetPanoId': panoramaId}); + } + }); + } /** diff --git a/public/javascripts/SVValidate/src/panorama/PanoramaContainer.js b/public/javascripts/SVValidate/src/panorama/PanoramaContainer.js index 1a23a73db6..c6aa563a3d 100644 --- a/public/javascripts/SVValidate/src/panorama/PanoramaContainer.js +++ b/public/javascripts/SVValidate/src/panorama/PanoramaContainer.js @@ -12,6 +12,7 @@ function PanoramaContainer (labelList) { progress: 0 // used to keep track of which index to retrieve from labels }; let self = this; + let panoHistories = []; /** * Initializes panorama(s) on the validate page. @@ -139,6 +140,27 @@ function PanoramaContainer (labelList) { svv.panorama.setProperty('validationTimestamp', timestamp); } + /** + * Adds a panorama history to the list of panorama histories. + */ + function addPanoHistory(panoHistory) { + panoHistories.push(panoHistory); + } + + /** + * Returns a list of all the currently tracked panorama histories. + */ + function getPanoHistories() { + return panoHistories; + } + + /** + * Clears the list of all the currently tracked panorama histories. + */ + function clearPanoHistories() { + panoHistories = []; + } + self.fetchNewLabel = fetchNewLabel; self.getProperty = getProperty; self.loadNewLabelOntoPanorama = loadNewLabelOntoPanorama; @@ -147,6 +169,9 @@ function PanoramaContainer (labelList) { self.reset = reset; self.setLabelList = setLabelList; self.validateLabel = validateLabel; + self.addPanoHistory = addPanoHistory; + self.getPanoHistories = getPanoHistories; + self.clearPanoHistories = clearPanoHistories; _init();