forked from MapComplete/MapComplete
		
	Scripts: add script to fix panoramax-hashes; see #2372
This commit is contained in:
		
							parent
							
								
									1493c00edf
								
							
						
					
					
						commit
						c4f0e18b9e
					
				
					 3 changed files with 153 additions and 10 deletions
				
			
		
							
								
								
									
										117
									
								
								scripts/repairPanoramax.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								scripts/repairPanoramax.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,117 @@
 | 
				
			||||||
 | 
					import Script from "./Script"
 | 
				
			||||||
 | 
					import { Overpass } from "../src/Logic/Osm/Overpass"
 | 
				
			||||||
 | 
					import { Or } from "../src/Logic/Tags/Or"
 | 
				
			||||||
 | 
					import { RegexTag } from "../src/Logic/Tags/RegexTag"
 | 
				
			||||||
 | 
					import { Utils } from "../src/Utils"
 | 
				
			||||||
 | 
					import Constants from "../src/Models/Constants"
 | 
				
			||||||
 | 
					import { ImmutableStore } from "../src/Logic/UIEventSource"
 | 
				
			||||||
 | 
					import { BBox } from "../src/Logic/BBox"
 | 
				
			||||||
 | 
					import ChangeTagAction from "../src/Logic/Osm/Actions/ChangeTagAction"
 | 
				
			||||||
 | 
					import { Tag } from "../src/Logic/Tags/Tag"
 | 
				
			||||||
 | 
					import { Panoramax } from "panoramax-js/dist"
 | 
				
			||||||
 | 
					import { Changes } from "../src/Logic/Osm/Changes"
 | 
				
			||||||
 | 
					import OsmChangeAction from "../src/Logic/Osm/Actions/OsmChangeAction"
 | 
				
			||||||
 | 
					import { writeFileSync } from "fs"
 | 
				
			||||||
 | 
					import { Feature } from "geojson"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RepairPanoramax extends Script {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static readonly europe: Feature  =    {
 | 
				
			||||||
 | 
					        "type": "Feature",
 | 
				
			||||||
 | 
					        "properties": {},
 | 
				
			||||||
 | 
					        "geometry": {
 | 
				
			||||||
 | 
					            "coordinates": [
 | 
				
			||||||
 | 
					                [
 | 
				
			||||||
 | 
					                    [
 | 
				
			||||||
 | 
					                        -20.091159690050006,
 | 
				
			||||||
 | 
					                        25.773375277790038
 | 
				
			||||||
 | 
					                    ],
 | 
				
			||||||
 | 
					                    [
 | 
				
			||||||
 | 
					                        46.12276429398841,
 | 
				
			||||||
 | 
					                        25.773375277790038
 | 
				
			||||||
 | 
					                    ],
 | 
				
			||||||
 | 
					                    [
 | 
				
			||||||
 | 
					                        46.12276429398841,
 | 
				
			||||||
 | 
					                        65.41389761819318
 | 
				
			||||||
 | 
					                    ],
 | 
				
			||||||
 | 
					                    [
 | 
				
			||||||
 | 
					                        -20.091159690050006,
 | 
				
			||||||
 | 
					                        65.41389761819318
 | 
				
			||||||
 | 
					                    ],
 | 
				
			||||||
 | 
					                    [
 | 
				
			||||||
 | 
					                        -20.091159690050006,
 | 
				
			||||||
 | 
					                        25.773375277790038
 | 
				
			||||||
 | 
					                    ]
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "type": "Polygon"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor() {
 | 
				
			||||||
 | 
					        super("See https://source.mapcomplete.org/MapComplete/MapComplete/issues/2372\n" +
 | 
				
			||||||
 | 
					            "We accidentally added the full image URL instead of the hash due to a bug. This scripts rewrites all")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async main(args: string[]): Promise<void> {
 | 
				
			||||||
 | 
					        const keys = ["panoramax", ...Utils.TimesT(10, i => "panoramax:" + i)]
 | 
				
			||||||
 | 
					        const overpass = new Overpass(
 | 
				
			||||||
 | 
					            new Or(
 | 
				
			||||||
 | 
					                keys.map(k => new RegexTag(k, /^https:\/\/panoramax.mapcomplete.org\/.*/))
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            [],
 | 
				
			||||||
 | 
					            Constants.defaultOverpassUrls[0],
 | 
				
			||||||
 | 
					            new ImmutableStore(500)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const [wrongFeatures] = await overpass.queryGeoJson(BBox.global)
 | 
				
			||||||
 | 
					        const allChanges: OsmChangeAction[] = []
 | 
				
			||||||
 | 
					        for (const f of wrongFeatures.features) {
 | 
				
			||||||
 | 
					            for (const key of keys) {
 | 
				
			||||||
 | 
					                const v = f.properties[key]
 | 
				
			||||||
 | 
					                if (!v) {
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                const pre = "https://panoramax.mapcomplete.org/api/pictures/"
 | 
				
			||||||
 | 
					                const pre1 = "https://panoramax.mapcomplete.org/permanent/"
 | 
				
			||||||
 | 
					                let correct: string
 | 
				
			||||||
 | 
					                if (v.startsWith(pre)) {
 | 
				
			||||||
 | 
					                    correct = v.substring(pre.length)
 | 
				
			||||||
 | 
					                    correct = correct.substring(0, correct.indexOf("/"))
 | 
				
			||||||
 | 
					                } else if (v.startsWith(pre1)) {
 | 
				
			||||||
 | 
					                    const stripped = v.substring(pre1.length)
 | 
				
			||||||
 | 
					                    correct = stripped.replace(/\//g, "").replace(/\.jpg$/, "")
 | 
				
			||||||
 | 
					                    correct = correct.substring(0, 8) + "-" + correct.substring(8)
 | 
				
			||||||
 | 
					                } else if (Panoramax.isId(v)) {
 | 
				
			||||||
 | 
					                    // This is a valid ID that came on an object also having an _invalid_ id
 | 
				
			||||||
 | 
					                    // We can safely skip this
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    throw "Unknown url " + v
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                console.log(key, correct, "    old: ", v)
 | 
				
			||||||
 | 
					                if (!Panoramax.isId(correct)) {
 | 
				
			||||||
 | 
					                    throw "Constructed an invalid id:" + correct
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                const change = new ChangeTagAction(
 | 
				
			||||||
 | 
					                    f.properties.id,
 | 
				
			||||||
 | 
					                    new Tag(key, correct),
 | 
				
			||||||
 | 
					                    f.properties,
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        theme: "fix",
 | 
				
			||||||
 | 
					                        changeType: "fix"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                allChanges.push(change)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const xml = await Changes.createChangesetXMLForJosm(allChanges)
 | 
				
			||||||
 | 
					        console.log(xml)
 | 
				
			||||||
 | 
					        const path = "repairPanoramax.osc"
 | 
				
			||||||
 | 
					        writeFileSync(path, xml)
 | 
				
			||||||
 | 
					        console.log("Written XML to", path)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					new RepairPanoramax().run()
 | 
				
			||||||
| 
						 | 
					@ -95,8 +95,34 @@ export class Changes {
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static async createChangesetXMLForJosm(actions: OsmChangeAction[], osmConnection?: OsmConnection): Promise<string> {
 | 
				
			||||||
 | 
					        osmConnection ??= new OsmConnection()
 | 
				
			||||||
 | 
					        const changes = new Changes({
 | 
				
			||||||
 | 
					            osmConnection
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        const descriptions: ChangeDescription[] = []
 | 
				
			||||||
 | 
					        for (const action of actions) {
 | 
				
			||||||
 | 
					            descriptions.push(...await action.Perform(changes))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const downloader = new OsmObjectDownloader(osmConnection.Backend(), undefined)
 | 
				
			||||||
 | 
					        const downloaded: OsmObject[] = []
 | 
				
			||||||
 | 
					        for (const action of actions) {
 | 
				
			||||||
 | 
					            const osmObj = await downloader.DownloadObjectAsync(action.mainObjectId)
 | 
				
			||||||
 | 
					            if (osmObj === "deleted") {
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            downloaded.push(osmObj)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return Changes.buildChangesetXML("", changes.CreateChangesetObjects(descriptions, downloaded))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Creates a changeset
 | 
				
			||||||
 | 
					     * @param csId either the ID-number of the changeset, or an empty string (e.g. when uploading with JOSM)
 | 
				
			||||||
 | 
					     * @param allChanges use 'new Changes()
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    static buildChangesetXML(
 | 
					    static buildChangesetXML(
 | 
				
			||||||
        csId: string,
 | 
					        csId: number | string,
 | 
				
			||||||
        allChanges: {
 | 
					        allChanges: {
 | 
				
			||||||
            modifiedObjects: OsmObject[]
 | 
					            modifiedObjects: OsmObject[]
 | 
				
			||||||
            newObjects: OsmObject[]
 | 
					            newObjects: OsmObject[]
 | 
				
			||||||
| 
						 | 
					@ -111,20 +137,20 @@ export class Changes {
 | 
				
			||||||
        if (newElements.length > 0) {
 | 
					        if (newElements.length > 0) {
 | 
				
			||||||
            changes +=
 | 
					            changes +=
 | 
				
			||||||
                "\n<create>\n" +
 | 
					                "\n<create>\n" +
 | 
				
			||||||
                newElements.map((e) => e.ChangesetXML(csId)).join("\n") +
 | 
					                newElements.map((e) => e.ChangesetXML("" + csId)).join("\n") +
 | 
				
			||||||
                "</create>"
 | 
					                "</create>"
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (changedElements.length > 0) {
 | 
					        if (changedElements.length > 0) {
 | 
				
			||||||
            changes +=
 | 
					            changes +=
 | 
				
			||||||
                "\n<modify>\n" +
 | 
					                "\n<modify>\n" +
 | 
				
			||||||
                changedElements.map((e) => e.ChangesetXML(csId)).join("\n") +
 | 
					                changedElements.map((e) => e.ChangesetXML("" + csId)).join("\n") +
 | 
				
			||||||
                "\n</modify>"
 | 
					                "\n</modify>"
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (deletedElements.length > 0) {
 | 
					        if (deletedElements.length > 0) {
 | 
				
			||||||
            changes +=
 | 
					            changes +=
 | 
				
			||||||
                "\n<delete>\n" +
 | 
					                "\n<delete>\n" +
 | 
				
			||||||
                deletedElements.map((e) => e.ChangesetXML(csId)).join("\n") +
 | 
					                deletedElements.map((e) => e.ChangesetXML("" + csId)).join("\n") +
 | 
				
			||||||
                "\n</delete>"
 | 
					                "\n</delete>"
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -722,7 +748,7 @@ export class Changes {
 | 
				
			||||||
                    deletedObjects: OsmObject[]
 | 
					                    deletedObjects: OsmObject[]
 | 
				
			||||||
                } = this.CreateChangesetObjects(toUpload, objects)
 | 
					                } = this.CreateChangesetObjects(toUpload, objects)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return Changes.buildChangesetXML("" + csId, changes)
 | 
					                return Changes.buildChangesetXML(csId, changes)
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            metatags,
 | 
					            metatags,
 | 
				
			||||||
            openChangeset
 | 
					            openChangeset
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,10 +3,10 @@ import { Utils } from "../../Utils"
 | 
				
			||||||
import { ImmutableStore, Store } from "../UIEventSource"
 | 
					import { ImmutableStore, Store } from "../UIEventSource"
 | 
				
			||||||
import { BBox } from "../BBox"
 | 
					import { BBox } from "../BBox"
 | 
				
			||||||
import osmtogeojson from "osmtogeojson"
 | 
					import osmtogeojson from "osmtogeojson"
 | 
				
			||||||
import { FeatureCollection } from "@turf/turf"
 | 
					import { FeatureCollection, Geometry } from "geojson"
 | 
				
			||||||
import { Geometry } from "geojson"
 | 
					 | 
				
			||||||
import { OsmTags } from "../../Models/OsmFeature"
 | 
					import { OsmTags } from "../../Models/OsmFeature"
 | 
				
			||||||
;("use strict")
 | 
					
 | 
				
			||||||
 | 
					("use strict")
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Interfaces overpass to get all the latest data
 | 
					 * Interfaces overpass to get all the latest data
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -64,14 +64,14 @@ export class Overpass {
 | 
				
			||||||
            elements: []
 | 
					            elements: []
 | 
				
			||||||
            remark
 | 
					            remark
 | 
				
			||||||
            osm3s: { timestamp_osm_base: string }
 | 
					            osm3s: { timestamp_osm_base: string }
 | 
				
			||||||
        }>(this.buildUrl(query))
 | 
					        }>(this.buildUrl(query), {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (json.elements.length === 0 && json.remark !== undefined) {
 | 
					        if (json.elements.length === 0 && json.remark !== undefined) {
 | 
				
			||||||
            console.warn("Timeout or other runtime error while querying overpass", json.remark)
 | 
					            console.warn("Timeout or other runtime error while querying overpass", json.remark)
 | 
				
			||||||
            throw `Runtime error (timeout or similar)${json.remark}`
 | 
					            throw `Runtime error (timeout or similar)${json.remark}`
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (json.elements.length === 0) {
 | 
					        if (json.elements.length === 0) {
 | 
				
			||||||
            console.warn("No features for", json)
 | 
					            console.warn("No features for", this.buildUrl(query))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const geojson = <FeatureCollection<Geometry, OsmTags>>osmtogeojson(json)
 | 
					        const geojson = <FeatureCollection<Geometry, OsmTags>>osmtogeojson(json)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue