| 
									
										
										
										
											2020-11-18 12:50:28 +01:00
										 |  |  | import escapeHtml from "escape-html"; | 
					
						
							| 
									
										
										
										
											2021-01-04 04:36:21 +01:00
										 |  |  | // @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  | import {OsmConnection, UserDetails} from "./OsmConnection"; | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  | import {UIEventSource} from "../UIEventSource"; | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  | import {ElementStorage} from "../ElementStorage"; | 
					
						
							| 
									
										
										
										
											2020-10-02 19:00:24 +02:00
										 |  |  | import State from "../../State"; | 
					
						
							| 
									
										
										
										
											2020-09-21 23:57:50 +02:00
										 |  |  | import Locale from "../../UI/i18n/Locale"; | 
					
						
							| 
									
										
										
										
											2020-11-11 16:23:49 +01:00
										 |  |  | import LayoutConfig from "../../Customizations/JSON/LayoutConfig"; | 
					
						
							| 
									
										
										
										
											2021-01-02 19:09:49 +01:00
										 |  |  | import Constants from "../../Models/Constants"; | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | export class ChangesetHandler { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-15 02:29:31 +02:00
										 |  |  |     private readonly _dryRun: boolean; | 
					
						
							|  |  |  |     private readonly userDetails: UIEventSource<UserDetails>; | 
					
						
							|  |  |  |     private readonly auth: any; | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-15 02:29:31 +02:00
										 |  |  |     public readonly currentChangeset: UIEventSource<string>; | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-27 18:44:16 +02:00
										 |  |  |     constructor(layoutName: string, dryRun: boolean, osmConnection: OsmConnection, auth) { | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |         this._dryRun = dryRun; | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  |         this.userDetails = osmConnection.userDetails; | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |         this.auth = auth; | 
					
						
							| 
									
										
										
										
											2020-08-27 18:44:16 +02:00
										 |  |  |         this.currentChangeset = osmConnection.GetPreference("current-open-changeset-" + layoutName); | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (dryRun) { | 
					
						
							|  |  |  |             console.log("DRYRUN ENABLED"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |     public UploadChangeset( | 
					
						
							| 
									
										
										
										
											2020-11-11 16:23:49 +01:00
										 |  |  |         layout: LayoutConfig, | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |         allElements: ElementStorage, | 
					
						
							|  |  |  |         generateChangeXML: (csid: string) => string, | 
					
						
							|  |  |  |          continuation: () => void) { | 
					
						
							| 
									
										
										
										
											2020-09-15 02:29:31 +02:00
										 |  |  |          | 
					
						
							|  |  |  |         if(this.userDetails.data.csCount == 0){ | 
					
						
							|  |  |  |             // The user became a contributor!
 | 
					
						
							|  |  |  |             this.userDetails.data.csCount = 1; | 
					
						
							|  |  |  |             this.userDetails.ping(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (this._dryRun) { | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |             const changesetXML = generateChangeXML("123456"); | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |             console.log(changesetXML); | 
					
						
							|  |  |  |             continuation(); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const self = this; | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (this.currentChangeset.data === undefined || this.currentChangeset.data === "") { | 
					
						
							|  |  |  |             // We have to open a new changeset
 | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |             this.OpenChangeset(layout,(csId) => { | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  |                 this.currentChangeset.setData(csId); | 
					
						
							| 
									
										
										
										
											2020-08-27 18:44:16 +02:00
										 |  |  |                 const changeset = generateChangeXML(csId); | 
					
						
							|  |  |  |                 console.log(changeset); | 
					
						
							|  |  |  |                 self.AddChange(csId, changeset, | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |                     allElements, | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  |                     () => { | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                     (e) => { | 
					
						
							|  |  |  |                         console.error("UPLOADING FAILED!", e) | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  |                 ) | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             // There still exists an open changeset (or at least we hope so)
 | 
					
						
							|  |  |  |             const csId = this.currentChangeset.data; | 
					
						
							|  |  |  |             self.AddChange( | 
					
						
							|  |  |  |                 csId, | 
					
						
							|  |  |  |                 generateChangeXML(csId), | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |                 allElements, | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  |                 () => { | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 (e) => { | 
					
						
							|  |  |  |                     console.warn("Could not upload, changeset is probably closed: ", e); | 
					
						
							|  |  |  |                     // Mark the CS as closed...
 | 
					
						
							|  |  |  |                     this.currentChangeset.setData(""); | 
					
						
							|  |  |  |                     // ... and try again. As the cs is closed, no recursive loop can exist  
 | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |                     self.UploadChangeset(layout, allElements, generateChangeXML, continuation); | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |     private OpenChangeset( | 
					
						
							| 
									
										
										
										
											2020-11-11 16:23:49 +01:00
										 |  |  |         layout : LayoutConfig, | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |         continuation: (changesetId: string) => void) { | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-11 16:23:49 +01:00
										 |  |  |         const commentExtra = layout.changesetmessage !== undefined ? " - " + layout.changesetmessage : ""; | 
					
						
							| 
									
										
										
										
											2020-09-30 22:22:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-21 23:57:50 +02:00
										 |  |  |         let surveySource = ""; | 
					
						
							| 
									
										
										
										
											2020-09-30 22:22:58 +02:00
										 |  |  |         if (State.state.currentGPSLocation.data !== undefined) { | 
					
						
							| 
									
										
										
										
											2020-09-21 23:57:50 +02:00
										 |  |  |             surveySource = '<tag k="source" v="survey"/>' | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-09-30 22:22:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |         this.auth.xhr({ | 
					
						
							|  |  |  |             method: 'PUT', | 
					
						
							|  |  |  |             path: '/api/0.6/changeset/create', | 
					
						
							|  |  |  |             options: {header: {'Content-Type': 'text/xml'}}, | 
					
						
							|  |  |  |             content: [`<osm><changeset>`, | 
					
						
							| 
									
										
										
										
											2021-01-02 19:09:49 +01:00
										 |  |  |                 `<tag k="created_by" v="MapComplete ${Constants.vNumber}" />`, | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |                 `<tag k="comment" v="Adding data with #MapComplete for theme #${layout.id}${commentExtra}"/>`, | 
					
						
							|  |  |  |                 `<tag k="theme" v="${layout.id}"/>`, | 
					
						
							| 
									
										
										
										
											2020-09-21 23:57:50 +02:00
										 |  |  |                 `<tag k="language" v="${Locale.language.data}"/>`, | 
					
						
							| 
									
										
										
										
											2021-01-02 19:09:49 +01:00
										 |  |  |                 `<tag k="host" v="${escapeHtml(window.location.host)}"/>`, | 
					
						
							| 
									
										
										
										
											2021-01-04 21:33:37 +01:00
										 |  |  |                 `<tag k="imagery" v="${State.state.backgroundLayer.data.id}"/>`, | 
					
						
							| 
									
										
										
										
											2020-09-21 23:57:50 +02:00
										 |  |  |                 surveySource, | 
					
						
							| 
									
										
										
										
											2021-01-02 19:09:49 +01:00
										 |  |  |                 (layout.maintainer ?? "") !== "" ? `<tag k="theme-creator" v="${escapeHtml(layout.maintainer)}"/>` : "", | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |                 `</changeset></osm>`].join("") | 
					
						
							|  |  |  |         }, function (err, response) { | 
					
						
							|  |  |  |             if (response === undefined) { | 
					
						
							|  |  |  |                 console.log("err", err); | 
					
						
							|  |  |  |                 alert("Could not upload change (opening failed). Please file a bug report") | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 continuation(response); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private AddChange(changesetId: string, | 
					
						
							|  |  |  |                       changesetXML: string, | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |                       allElements: ElementStorage, | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  |                       continuation: ((changesetId: string, idMapping: any) => void), | 
					
						
							|  |  |  |                       onFail: ((changesetId: string) => void) = undefined) { | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |         this.auth.xhr({ | 
					
						
							|  |  |  |             method: 'POST', | 
					
						
							|  |  |  |             options: {header: {'Content-Type': 'text/xml'}}, | 
					
						
							|  |  |  |             path: '/api/0.6/changeset/' + changesetId + '/upload', | 
					
						
							|  |  |  |             content: changesetXML | 
					
						
							|  |  |  |         }, function (err, response) { | 
					
						
							|  |  |  |             if (response == null) { | 
					
						
							|  |  |  |                 console.log("err", err); | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  |                 if (onFail) { | 
					
						
							|  |  |  |                     onFail(changesetId); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |             const mapping = ChangesetHandler.parseUploadChangesetResponse(response, allElements); | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |             console.log("Uploaded changeset ", changesetId); | 
					
						
							|  |  |  |             continuation(changesetId, mapping); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  |     public CloseChangeset(changesetId: string = undefined, continuation: (() => void) = () => { | 
					
						
							|  |  |  |     }) { | 
					
						
							|  |  |  |         if (changesetId === undefined) { | 
					
						
							|  |  |  |             changesetId = this.currentChangeset.data; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (changesetId === undefined) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         console.log("closing changeset", changesetId); | 
					
						
							|  |  |  |         this.currentChangeset.setData(""); | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |         this.auth.xhr({ | 
					
						
							|  |  |  |             method: 'PUT', | 
					
						
							|  |  |  |             path: '/api/0.6/changeset/' + changesetId + '/close', | 
					
						
							|  |  |  |         }, function (err, response) { | 
					
						
							|  |  |  |             if (response == null) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 console.log("err", err); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  |             console.log("Closed changeset ", changesetId) | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if (continuation !== undefined) { | 
					
						
							|  |  |  |                 continuation(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |     private static parseUploadChangesetResponse(response: XMLDocument, allElements: ElementStorage) { | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |         const nodes = response.getElementsByTagName("node"); | 
					
						
							|  |  |  |         // @ts-ignore
 | 
					
						
							|  |  |  |         for (const node of nodes) { | 
					
						
							|  |  |  |             const oldId = parseInt(node.attributes.old_id.value); | 
					
						
							|  |  |  |             const newId = parseInt(node.attributes.new_id.value); | 
					
						
							|  |  |  |             if (oldId !== undefined && newId !== undefined && | 
					
						
							|  |  |  |                 !isNaN(oldId) && !isNaN(newId)) { | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  |                 if(oldId == newId){ | 
					
						
							|  |  |  |                     continue; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 console.log("Rewriting id: ", oldId, "-->", newId); | 
					
						
							| 
									
										
										
										
											2020-12-05 03:22:17 +01:00
										 |  |  |                 const element = allElements.getEventSourceById("node/" + oldId); | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  |                 element.data.id = "node/" + newId; | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |                 allElements.addElementById("node/" + newId, element); | 
					
						
							| 
									
										
										
										
											2020-08-27 11:11:20 +02:00
										 |  |  |                 element.ping(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |