forked from MapComplete/MapComplete
		
	Merge master
This commit is contained in:
		
						commit
						f20144a502
					
				
					 17 changed files with 420 additions and 56 deletions
				
			
		| 
						 | 
				
			
			@ -363,7 +363,7 @@ export class Changes {
 | 
			
		|||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private CreateChangesetObjects(changes: ChangeDescription[], downloadedOsmObjects: OsmObject[]): {
 | 
			
		||||
    public CreateChangesetObjects(changes: ChangeDescription[], downloadedOsmObjects: OsmObject[]): {
 | 
			
		||||
        newObjects: OsmObject[],
 | 
			
		||||
        modifiedObjects: OsmObject[]
 | 
			
		||||
        deletedObjects: OsmObject[]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,13 +51,14 @@ export class ChangesetHandler {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Inplace rewrite of extraMetaTags
 | 
			
		||||
     * If the metatags contain a special motivation of the format "<change-type>:node/-<number>", this method will rewrite this negative number to the actual ID
 | 
			
		||||
     * The key is changed _in place_; true will be returned if a change has been applied
 | 
			
		||||
     * @param extraMetaTags
 | 
			
		||||
     * @param rewriteIds
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private static rewriteMetaTags(extraMetaTags: ChangesetTag[], rewriteIds: Map<string, string>) {
 | 
			
		||||
    static rewriteMetaTags(extraMetaTags: ChangesetTag[], rewriteIds: Map<string, string>) {
 | 
			
		||||
        let hasChange = false;
 | 
			
		||||
        for (const tag of extraMetaTags) {
 | 
			
		||||
            const match = tag.key.match(/^([a-zA-Z0-9_]+):(node\/-[0-9])$/)
 | 
			
		||||
| 
						 | 
				
			
			@ -92,6 +93,8 @@ export class ChangesetHandler {
 | 
			
		|||
        if (!extraMetaTags.some(tag => tag.key === "comment") || !extraMetaTags.some(tag => tag.key === "theme")) {
 | 
			
		||||
            throw "The meta tags should at least contain a `comment` and a `theme`"
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        extraMetaTags = [...extraMetaTags, ...this.defaultChangesetTags()]
 | 
			
		||||
 | 
			
		||||
        if (this.userDetails.data.csCount == 0) {
 | 
			
		||||
            // The user became a contributor!
 | 
			
		||||
| 
						 | 
				
			
			@ -112,7 +115,7 @@ export class ChangesetHandler {
 | 
			
		|||
                openChangeset.setData(csId);
 | 
			
		||||
                const changeset = generateChangeXML(csId);
 | 
			
		||||
                console.trace("Opened a new changeset (openChangeset.data is undefined):", changeset);
 | 
			
		||||
                const changes = await this.AddChange(csId, changeset)
 | 
			
		||||
                const changes = await this.UploadChange(csId, changeset)
 | 
			
		||||
                const hasSpecialMotivationChanges = ChangesetHandler.rewriteMetaTags(extraMetaTags, changes)
 | 
			
		||||
                if(hasSpecialMotivationChanges){
 | 
			
		||||
                    // At this point, 'extraMetaTags' will have changed - we need to set the tags again
 | 
			
		||||
| 
						 | 
				
			
			@ -139,11 +142,12 @@ export class ChangesetHandler {
 | 
			
		|||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                const rewritings = await this.AddChange(
 | 
			
		||||
                const rewritings = await this.UploadChange(
 | 
			
		||||
                    csId,
 | 
			
		||||
                    generateChangeXML(csId))
 | 
			
		||||
 | 
			
		||||
                await this.RewriteTagsOf(extraMetaTags, rewritings, oldChangesetMeta)
 | 
			
		||||
                const rewrittenTags = this.RewriteTagsOf(extraMetaTags, rewritings, oldChangesetMeta)
 | 
			
		||||
                await this.UpdateTags(csId, rewrittenTags)
 | 
			
		||||
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                console.warn("Could not upload, changeset is probably closed: ", e);
 | 
			
		||||
| 
						 | 
				
			
			@ -153,13 +157,13 @@ export class ChangesetHandler {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the metatag of a changeset -
 | 
			
		||||
     * Given an existing changeset with metadata and extraMetaTags to add, will fuse them to a new set of metatags
 | 
			
		||||
     * Does not yet send data
 | 
			
		||||
     * @param extraMetaTags: new changeset tags to add/fuse with this changeset
 | 
			
		||||
     * @param rewriteIds: the mapping of ids
 | 
			
		||||
     * @param oldChangesetMeta: the metadata-object of the already existing changeset
 | 
			
		||||
     * @constructor
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private async RewriteTagsOf(extraMetaTags: ChangesetTag[],
 | 
			
		||||
    public RewriteTagsOf(extraMetaTags: ChangesetTag[],
 | 
			
		||||
                                rewriteIds: Map<string, string>,
 | 
			
		||||
                                oldChangesetMeta: {
 | 
			
		||||
                                    open: boolean,
 | 
			
		||||
| 
						 | 
				
			
			@ -167,9 +171,8 @@ export class ChangesetHandler {
 | 
			
		|||
                                    uid: number, // User ID
 | 
			
		||||
                                    changes_count: number,
 | 
			
		||||
                                    tags: any
 | 
			
		||||
                                }) {
 | 
			
		||||
                                }) : ChangesetTag[] {
 | 
			
		||||
 | 
			
		||||
        const csId = oldChangesetMeta.id
 | 
			
		||||
 | 
			
		||||
        // Note: extraMetaTags is where all the tags are collected into
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -214,10 +217,8 @@ export class ChangesetHandler {
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
        ChangesetHandler.rewriteMetaTags(extraMetaTags, rewriteIds)
 | 
			
		||||
 | 
			
		||||
        await this.UpdateTags(csId, extraMetaTags)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        return extraMetaTags
 | 
			
		||||
    
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private handleIdRewrite(node: any, type: string): [string, string] {
 | 
			
		||||
| 
						 | 
				
			
			@ -295,7 +296,7 @@ export class ChangesetHandler {
 | 
			
		|||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async GetChangesetMeta(csId: number): Promise<{
 | 
			
		||||
    async GetChangesetMeta(csId: number): Promise<{
 | 
			
		||||
        id: number,
 | 
			
		||||
        open: boolean,
 | 
			
		||||
        uid: number,
 | 
			
		||||
| 
						 | 
				
			
			@ -340,21 +341,30 @@ export class ChangesetHandler {
 | 
			
		|||
            });
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private defaultChangesetTags() : ChangesetTag[]{
 | 
			
		||||
      return  [ ["created_by", `MapComplete ${Constants.vNumber}`],
 | 
			
		||||
            ["locale", Locale.language.data],
 | 
			
		||||
            ["host", `${window.location.origin}${window.location.pathname}`],
 | 
			
		||||
            ["source", this.changes.state["currentUserLocation"]?.features?.data?.length > 0 ? "survey" : undefined],
 | 
			
		||||
            ["imagery", this.changes.state["backgroundLayer"]?.data?.id]].map(([key, value]) => ({
 | 
			
		||||
            key, value, aggretage: false
 | 
			
		||||
        }))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens a changeset with the specified tags
 | 
			
		||||
     * @param changesetTags
 | 
			
		||||
     * @constructor
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private OpenChangeset(
 | 
			
		||||
        changesetTags: ChangesetTag[]
 | 
			
		||||
    ): Promise<number> {
 | 
			
		||||
        const self = this;
 | 
			
		||||
        return new Promise<number>(function (resolve, reject) {
 | 
			
		||||
 | 
			
		||||
            const metadata = [
 | 
			
		||||
                ["created_by", `MapComplete ${Constants.vNumber}`],
 | 
			
		||||
                ["locale", Locale.language.data],
 | 
			
		||||
                ["host", `${window.location.origin}${window.location.pathname}`],
 | 
			
		||||
                ["source", self.changes.state["currentUserLocation"]?.features?.data?.length > 0 ? "survey" : undefined],
 | 
			
		||||
                ["imagery", self.changes.state["backgroundLayer"]?.data?.id],
 | 
			
		||||
                ...changesetTags.map(cstag => [cstag.key, cstag.value])
 | 
			
		||||
            ]
 | 
			
		||||
            const metadata = changesetTags.map(cstag => [cstag.key, cstag.value])
 | 
			
		||||
                .filter(kv => (kv[1] ?? "") !== "")
 | 
			
		||||
                .map(kv => `<tag k="${kv[0]}" v="${escapeHtml(kv[1])}"/>`)
 | 
			
		||||
                .join("\n")
 | 
			
		||||
| 
						 | 
				
			
			@ -382,7 +392,7 @@ export class ChangesetHandler {
 | 
			
		|||
    /**
 | 
			
		||||
     * Upload a changesetXML
 | 
			
		||||
     */
 | 
			
		||||
    private AddChange(changesetId: number,
 | 
			
		||||
    private UploadChange(changesetId: number,
 | 
			
		||||
                      changesetXML: string): Promise<Map<string, string>> {
 | 
			
		||||
        const self = this;
 | 
			
		||||
        return new Promise(function (resolve, reject) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -291,7 +291,20 @@
 | 
			
		|||
            "it": "Accessibile pubblicamente",
 | 
			
		||||
            "de": "Zugänglich für die Allgemeinheit",
 | 
			
		||||
            "fr": "Accessible au public"
 | 
			
		||||
          }
 | 
			
		||||
          },
 | 
			
		||||
          "addExtraTags": [
 | 
			
		||||
            "fee=no"
 | 
			
		||||
          ]
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "if": "fee=yes",
 | 
			
		||||
          "then": {
 | 
			
		||||
            "en": "This is a <b>paid</b> playground",
 | 
			
		||||
            "nl": "Er moet <b>betaald</b> worden om deze speeltuin te mogen gebruiken"
 | 
			
		||||
          },
 | 
			
		||||
          "addExtraTags": [
 | 
			
		||||
            "access=customers"
 | 
			
		||||
          ]
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "if": "access=customers",
 | 
			
		||||
| 
						 | 
				
			
			@ -301,7 +314,10 @@
 | 
			
		|||
            "it": "Accessibile solamente ai clienti dell’attività che lo gestisce",
 | 
			
		||||
            "de": "Nur für Kunden des Betreibers zugänglich",
 | 
			
		||||
            "fr": "Réservée aux clients"
 | 
			
		||||
          }
 | 
			
		||||
          },
 | 
			
		||||
          "addExtraTags": [
 | 
			
		||||
            "fee=no"
 | 
			
		||||
          ]
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "if": "access=students",
 | 
			
		||||
| 
						 | 
				
			
			@ -312,7 +328,10 @@
 | 
			
		|||
            "de": "Nur für Schüler der Schule zugänglich",
 | 
			
		||||
            "fr": "Réservée aux élèves de l’école"
 | 
			
		||||
          },
 | 
			
		||||
          "hideInAnswer": true
 | 
			
		||||
          "hideInAnswer": true,
 | 
			
		||||
          "addExtraTags": [
 | 
			
		||||
            "fee=no"
 | 
			
		||||
          ]
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "if": "access=private",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,8 @@
 | 
			
		|||
        "delete": "Supprimer",
 | 
			
		||||
        "explanations": {
 | 
			
		||||
            "hardDelete": "Ce point sera supprimé d’OpenStreetmap. Il pourra être restauré par des méthodes avancées",
 | 
			
		||||
            "selectReason": "Sélectionner pourquoi cet élément devrait être supprimé"
 | 
			
		||||
            "selectReason": "Sélectionner pourquoi cet élément devrait être supprimé",
 | 
			
		||||
            "softDelete": "Cet objet sera mis à jour et caché de l'application. <span class=\"subtle\">{reason}</span>"
 | 
			
		||||
        },
 | 
			
		||||
        "isDeleted": "Cet objet est supprimé",
 | 
			
		||||
        "isntAPoint": "Seul les points peuvent être supprimés, l'objet sélectionné est une ligne, un polygone ou une relation.",
 | 
			
		||||
| 
						 | 
				
			
			@ -56,7 +57,12 @@
 | 
			
		|||
            "title": "Ajouter un nouveau point ?",
 | 
			
		||||
            "warnVisibleForEveryone": "Votre ajout sera visible",
 | 
			
		||||
            "zoomInFurther": "Rapprochez vous pour ajouter un point.",
 | 
			
		||||
            "zoomInMore": "Zoomez pour importer cet élément"
 | 
			
		||||
            "zoomInMore": "Zoomez pour importer cet élément",
 | 
			
		||||
            "import": {
 | 
			
		||||
                "howToTest": "Pour essayer, ajouter <b>test=true</b> ou <b>backend=osm-test</b> à l'adresse de la page. Le groupe de modifications sera affiché dans la console. Merci d'ouvrir un PR pour officialiser ce thème et ainsi activer le bouton d'import.",
 | 
			
		||||
                "importTags": "L'objet recevra {tags}",
 | 
			
		||||
                "hasBeenImported": "Cet objet a été importé"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "attribution": {
 | 
			
		||||
            "attributionContent": "<p>Toutes les données sont fournies par <a href='https://osm.org' target='_blank'>OpenStreetMap</a>, librement réutilisables sous <a href='https://osm.org/copyright' target='_blank'>Open DataBase License</a>.</p>",
 | 
			
		||||
| 
						 | 
				
			
			@ -283,4 +289,4 @@
 | 
			
		|||
        "split": "Couper",
 | 
			
		||||
        "splitTitle": "Choisissez sur la carte où couper cette route"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2334,13 +2334,13 @@
 | 
			
		|||
                    "0": {
 | 
			
		||||
                        "then": "Zugänglich für die Allgemeinheit"
 | 
			
		||||
                    },
 | 
			
		||||
                    "1": {
 | 
			
		||||
                    "2": {
 | 
			
		||||
                        "then": "Nur für Kunden des Betreibers zugänglich"
 | 
			
		||||
                    },
 | 
			
		||||
                    "2": {
 | 
			
		||||
                    "3": {
 | 
			
		||||
                        "then": "Nur für Schüler der Schule zugänglich"
 | 
			
		||||
                    },
 | 
			
		||||
                    "3": {
 | 
			
		||||
                    "4": {
 | 
			
		||||
                        "then": "Nicht zugänglich"
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3944,12 +3944,15 @@
 | 
			
		|||
                        "then": "Accessible to the general public"
 | 
			
		||||
                    },
 | 
			
		||||
                    "1": {
 | 
			
		||||
                        "then": "Only accessible for clients of the operating business"
 | 
			
		||||
                        "then": "This is a <b>paid</b> playground"
 | 
			
		||||
                    },
 | 
			
		||||
                    "2": {
 | 
			
		||||
                        "then": "Only accessible to students of the school"
 | 
			
		||||
                        "then": "Only accessible for clients of the operating business"
 | 
			
		||||
                    },
 | 
			
		||||
                    "3": {
 | 
			
		||||
                        "then": "Only accessible to students of the school"
 | 
			
		||||
                    },
 | 
			
		||||
                    "4": {
 | 
			
		||||
                        "then": "Not accessible"
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -210,7 +210,8 @@
 | 
			
		|||
                "render": "Espace entre deux barrières successives : {width:separation} m"
 | 
			
		||||
            },
 | 
			
		||||
            "Width of opening (cyclebarrier)": {
 | 
			
		||||
                "render": "Largeur de l'ouverture : {width:opening} m"
 | 
			
		||||
                "render": "Largeur de l'ouverture : {width:opening} m",
 | 
			
		||||
                "question": "Quelle est la largeur d'ouverture la plus petite près de la barrière ?"
 | 
			
		||||
            },
 | 
			
		||||
            "bicycle=yes/no": {
 | 
			
		||||
                "mappings": {
 | 
			
		||||
| 
						 | 
				
			
			@ -220,6 +221,17 @@
 | 
			
		|||
                    "1": {
 | 
			
		||||
                        "then": "Un cycliste ne peut pas franchir ceci."
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                "question": "Est-ce qu'un vélo peut franchir cette barrière ?"
 | 
			
		||||
            },
 | 
			
		||||
            "barrier_type": {
 | 
			
		||||
                "mappings": {
 | 
			
		||||
                    "0": {
 | 
			
		||||
                        "then": "C'est un plot unique sur la route"
 | 
			
		||||
                    },
 | 
			
		||||
                    "1": {
 | 
			
		||||
                        "then": "C'est une barrière visant à ralentir les vélos"
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
| 
						 | 
				
			
			@ -323,7 +335,8 @@
 | 
			
		|||
        },
 | 
			
		||||
        "title": {
 | 
			
		||||
            "render": "Banc"
 | 
			
		||||
        }
 | 
			
		||||
        },
 | 
			
		||||
        "description": "Un banc est une surface en bois, métal, pierre... sur laquelle un humain peut s'asseoir. Cette couche permet de les visualiser et pose des questions à leur sujet."
 | 
			
		||||
    },
 | 
			
		||||
    "bench_at_pt": {
 | 
			
		||||
        "name": "Bancs des arrêts de transport en commun",
 | 
			
		||||
| 
						 | 
				
			
			@ -339,7 +352,8 @@
 | 
			
		|||
                    "2": {
 | 
			
		||||
                        "then": "Il n'y a pas de banc ici"
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                },
 | 
			
		||||
                "question": "Quel type de banc est-ce ?"
 | 
			
		||||
            },
 | 
			
		||||
            "bench_at_pt-name": {
 | 
			
		||||
                "render": "{name}"
 | 
			
		||||
| 
						 | 
				
			
			@ -355,7 +369,8 @@
 | 
			
		|||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "render": "Banc"
 | 
			
		||||
        }
 | 
			
		||||
        },
 | 
			
		||||
        "description": "Une couche montrant tous les arrêts de transports publics qui ont un banc"
 | 
			
		||||
    },
 | 
			
		||||
    "bicycle_library": {
 | 
			
		||||
        "description": "Un lieu où des vélos peuvent être empruntés pour un temps plus long",
 | 
			
		||||
| 
						 | 
				
			
			@ -1599,13 +1614,13 @@
 | 
			
		|||
                    "0": {
 | 
			
		||||
                        "then": "Accessible au public"
 | 
			
		||||
                    },
 | 
			
		||||
                    "1": {
 | 
			
		||||
                    "2": {
 | 
			
		||||
                        "then": "Réservée aux clients"
 | 
			
		||||
                    },
 | 
			
		||||
                    "2": {
 | 
			
		||||
                    "3": {
 | 
			
		||||
                        "then": "Réservée aux élèves de l’école"
 | 
			
		||||
                    },
 | 
			
		||||
                    "3": {
 | 
			
		||||
                    "4": {
 | 
			
		||||
                        "then": "Non accessible"
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
| 
						 | 
				
			
			@ -2381,5 +2396,18 @@
 | 
			
		|||
    },
 | 
			
		||||
    "watermill": {
 | 
			
		||||
        "name": "Moulin à eau"
 | 
			
		||||
    },
 | 
			
		||||
    "bicycle_rental": {
 | 
			
		||||
        "name": "Location de vélo",
 | 
			
		||||
        "description": "Station de location de vélo",
 | 
			
		||||
        "presets": {
 | 
			
		||||
            "0": {
 | 
			
		||||
                "description": "Un magasin avec employé(s) consacré à la location de vélos",
 | 
			
		||||
                "title": "magasin de location de vélos"
 | 
			
		||||
            },
 | 
			
		||||
            "1": {
 | 
			
		||||
                "title": "location de vélos"
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,8 +11,17 @@
 | 
			
		|||
                    "0": {
 | 
			
		||||
                        "then": "Bangunan ini tidak memiliki nomor rumah"
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                },
 | 
			
		||||
                "question": "Berapa nomor rumah ini?",
 | 
			
		||||
                "render": "Nomor rumah ini <b>{addr:housenumber}</b>"
 | 
			
		||||
            },
 | 
			
		||||
            "street": {
 | 
			
		||||
                "question": "Alamat ini di jalan apa?",
 | 
			
		||||
                "render": "Alamat ini ada di jalan <b>{addr:street}</b>"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "title": {
 | 
			
		||||
            "render": "Alamat yang diketahui"
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "artwork": {
 | 
			
		||||
| 
						 | 
				
			
			@ -377,5 +386,14 @@
 | 
			
		|||
    },
 | 
			
		||||
    "watermill": {
 | 
			
		||||
        "name": "Kincir Air"
 | 
			
		||||
    },
 | 
			
		||||
    "ambulancestation": {
 | 
			
		||||
        "name": "Peta stasiun ambulans",
 | 
			
		||||
        "presets": {
 | 
			
		||||
            "0": {
 | 
			
		||||
                "description": "Tambahkan stasiun ambulans ke peta",
 | 
			
		||||
                "title": "Stasiun ambulans"
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1287,13 +1287,13 @@
 | 
			
		|||
                    "0": {
 | 
			
		||||
                        "then": "Accessibile pubblicamente"
 | 
			
		||||
                    },
 | 
			
		||||
                    "1": {
 | 
			
		||||
                    "2": {
 | 
			
		||||
                        "then": "Accessibile solamente ai clienti dell’attività che lo gestisce"
 | 
			
		||||
                    },
 | 
			
		||||
                    "2": {
 | 
			
		||||
                    "3": {
 | 
			
		||||
                        "then": "Accessibile solamente agli studenti della scuola"
 | 
			
		||||
                    },
 | 
			
		||||
                    "3": {
 | 
			
		||||
                    "4": {
 | 
			
		||||
                        "then": "Non accessibile"
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3753,12 +3753,15 @@
 | 
			
		|||
                        "then": "Vrij toegankelijk voor het publiek"
 | 
			
		||||
                    },
 | 
			
		||||
                    "1": {
 | 
			
		||||
                        "then": "Enkel toegankelijk voor klanten van de bijhorende zaak"
 | 
			
		||||
                        "then": "Er moet <b>betaald</b> worden om deze speeltuin te mogen gebruiken"
 | 
			
		||||
                    },
 | 
			
		||||
                    "2": {
 | 
			
		||||
                        "then": "Enkel toegankelijk voor scholieren van de bijhorende school"
 | 
			
		||||
                        "then": "Enkel toegankelijk voor klanten van de bijhorende zaak"
 | 
			
		||||
                    },
 | 
			
		||||
                    "3": {
 | 
			
		||||
                        "then": "Enkel toegankelijk voor scholieren van de bijhorende school"
 | 
			
		||||
                    },
 | 
			
		||||
                    "4": {
 | 
			
		||||
                        "then": "Niet vrij toegankelijk"
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1078,7 +1078,7 @@
 | 
			
		|||
            },
 | 
			
		||||
            "playground-access": {
 | 
			
		||||
                "mappings": {
 | 
			
		||||
                    "3": {
 | 
			
		||||
                    "4": {
 | 
			
		||||
                        "then": "Недоступно"
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,9 @@
 | 
			
		|||
                },
 | 
			
		||||
                "3": {
 | 
			
		||||
                    "then": "Premier étage"
 | 
			
		||||
                },
 | 
			
		||||
                "4": {
 | 
			
		||||
                    "then": "Sous-sol"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "question": "À quel étage se situe l’élément ?",
 | 
			
		||||
| 
						 | 
				
			
			@ -111,6 +114,18 @@
 | 
			
		|||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "question": "Quel est l’élément Wikipédia correspondant ?"
 | 
			
		||||
        },
 | 
			
		||||
        "payment-options-advanced": {
 | 
			
		||||
            "override": {
 | 
			
		||||
                "mappings+": {
 | 
			
		||||
                    "0": {
 | 
			
		||||
                        "then": "Paiement via une application"
 | 
			
		||||
                    },
 | 
			
		||||
                    "1": {
 | 
			
		||||
                        "then": "Paiement via une carte de membre"
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -561,6 +561,26 @@
 | 
			
		|||
                "override": {
 | 
			
		||||
                    "=name": "Institutions d'éducation sans origine étymologique"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "5": {
 | 
			
		||||
                "override": {
 | 
			
		||||
                    "=name": "Lieux touristiques sans origine étymologique"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "4": {
 | 
			
		||||
                "override": {
 | 
			
		||||
                    "=name": "Lieux culturels sans origine étymologique"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "6": {
 | 
			
		||||
                "override": {
 | 
			
		||||
                    "=name": "Établissements sociaux ou de soins sans origine étymologique"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "7": {
 | 
			
		||||
                "override": {
 | 
			
		||||
                    "=name": "Lieux sportifs sans origine étymologique"
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "shortDescription": "Quelle est l'origine de ce toponyme ?",
 | 
			
		||||
| 
						 | 
				
			
			@ -778,5 +798,10 @@
 | 
			
		|||
        "description": "Cartographions tous les arbres !",
 | 
			
		||||
        "shortDescription": "Carte des arbres",
 | 
			
		||||
        "title": "Arbres"
 | 
			
		||||
    },
 | 
			
		||||
    "bicycle_rental": {
 | 
			
		||||
        "shortDescription": "Une carte avec des stations et magasins de location de vélos",
 | 
			
		||||
        "title": "Location de vélos",
 | 
			
		||||
        "description": "Vous trouverez sur cette carte toutes les stations de location de vélo telles qu'elles sont référencées dans OpenStreetMap"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
    "generate:css": "tailwindcss -i index.css -o css/index-tailwind-output.css",
 | 
			
		||||
    "test": "ts-node test/TestAll.ts",
 | 
			
		||||
    "init": "npm ci && npm run generate && npm run generate:editor-layer-index && npm run generate:layouts && npm run clean",
 | 
			
		||||
    "add-weblate-upstream": "git remote add weblate-layers https://hosted.weblate.org/git/mapcomplete/layer-translations/ ; git remote update weblate-layers",
 | 
			
		||||
    "add-weblate-upstream": "git remote add weblate-layers https://hosted.weblate.org/git/mapcomplete/layer-translations/ ; git remote add weblate-core https://hosted.weblate.org/git/mapcomplete/layer-core/; git remote add weblate-themes https://hosted.weblate.org/git/mapcomplete/layer-themes/; git remote add weblate-github git@github.com:weblate/MapComplete.git",
 | 
			
		||||
    "fix-weblate": "git remote update weblate-layers; git merge weblate-layers/master",
 | 
			
		||||
    "generate:editor-layer-index": "ts-node scripts/downloadFile.ts https://osmlab.github.io/editor-layer-index/imagery.geojson assets/editor-layer-index.json",
 | 
			
		||||
    "generate:polygon-features": "ts-node scripts/downloadFile.ts  https://raw.githubusercontent.com/tyrasd/osm-polygon-features/master/polygon-features.json assets/polygon-features.json",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										51
									
								
								test/Changes.spec.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								test/Changes.spec.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,51 @@
 | 
			
		|||
import T from "./TestHelper";
 | 
			
		||||
import {Changes} from "../Logic/Osm/Changes";
 | 
			
		||||
import {ChangeDescription, ChangeDescriptionTools} from "../Logic/Osm/Actions/ChangeDescription";
 | 
			
		||||
 | 
			
		||||
export default class ChangesSpec extends T {
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super([
 | 
			
		||||
            ["Generate preXML from changeDescriptions", () => {
 | 
			
		||||
                const changeDescrs: ChangeDescription[] = [
 | 
			
		||||
                    {
 | 
			
		||||
                        type: "node",
 | 
			
		||||
                        id: -1,
 | 
			
		||||
                        changes: {
 | 
			
		||||
                            lat: 42,
 | 
			
		||||
                            lon: -8
 | 
			
		||||
                        },
 | 
			
		||||
                        tags: [{k: "someKey", v: "someValue"}],
 | 
			
		||||
                        meta: {
 | 
			
		||||
                            changeType: "create",
 | 
			
		||||
                            theme: "test"
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        type: "node",
 | 
			
		||||
                        id: -1,
 | 
			
		||||
                        tags: [{k: 'foo', v: 'bar'}],
 | 
			
		||||
                        meta: {
 | 
			
		||||
                            changeType: "answer",
 | 
			
		||||
                            theme: "test"
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                ]
 | 
			
		||||
                const c = new Changes()
 | 
			
		||||
               const descr = c.CreateChangesetObjects(
 | 
			
		||||
                    changeDescrs,
 | 
			
		||||
                    []
 | 
			
		||||
                )
 | 
			
		||||
                T.equals(0, descr.modifiedObjects.length)
 | 
			
		||||
                T.equals(0, descr.deletedObjects.length)
 | 
			
		||||
                T.equals(1, descr.newObjects.length)
 | 
			
		||||
                const ch = descr.newObjects[0]
 | 
			
		||||
                T.equals("bar", ch.tags["foo"])
 | 
			
		||||
                T.equals("someValue", ch.tags["someKey"])
 | 
			
		||||
            }]
 | 
			
		||||
        ]);
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										181
									
								
								test/ChangesetHandler.spec.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								test/ChangesetHandler.spec.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,181 @@
 | 
			
		|||
import T from "./TestHelper";
 | 
			
		||||
import {ChangesetHandler, ChangesetTag} from "../Logic/Osm/ChangesetHandler";
 | 
			
		||||
import {UIEventSource} from "../Logic/UIEventSource";
 | 
			
		||||
import {OsmConnection} from "../Logic/Osm/OsmConnection";
 | 
			
		||||
import {ElementStorage} from "../Logic/ElementStorage";
 | 
			
		||||
import {Changes} from "../Logic/Osm/Changes";
 | 
			
		||||
 | 
			
		||||
export default class ChangesetHandlerSpec extends T {
 | 
			
		||||
    
 | 
			
		||||
    private static asDict(tags: {key: string, value: string | number}[]) : Map<string, string | number>{
 | 
			
		||||
        const d= new Map<string, string | number>()
 | 
			
		||||
 | 
			
		||||
        for (const tag of tags) {
 | 
			
		||||
            d.set(tag.key, tag.value)
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return d
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super([
 | 
			
		||||
            [
 | 
			
		||||
                "Test rewrite tags", () => {
 | 
			
		||||
                const cs = new ChangesetHandler(new UIEventSource<boolean>(true),
 | 
			
		||||
                    new OsmConnection({}),
 | 
			
		||||
                    new ElementStorage(),
 | 
			
		||||
                    new Changes(),
 | 
			
		||||
                    new UIEventSource(undefined)
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                const oldChangesetMeta = {
 | 
			
		||||
                    "type": "changeset",
 | 
			
		||||
                    "id": 118443748,
 | 
			
		||||
                    "created_at": "2022-03-13T19:52:10Z",
 | 
			
		||||
                    "closed_at": "2022-03-13T20:54:35Z",
 | 
			
		||||
                    "open": false,
 | 
			
		||||
                    "user": "Pieter Vander Vennet",
 | 
			
		||||
                    "uid": 3818858,
 | 
			
		||||
                    "minlat": 51.0361902,
 | 
			
		||||
                    "minlon": 3.7092939,
 | 
			
		||||
                    "maxlat": 51.0364194,
 | 
			
		||||
                    "maxlon": 3.7099520,
 | 
			
		||||
                    "comments_count": 0,
 | 
			
		||||
                    "changes_count": 3,
 | 
			
		||||
                    "tags": {
 | 
			
		||||
                        "answer": "5",
 | 
			
		||||
                        "comment": "Adding data with #MapComplete for theme #toerisme_vlaanderen",
 | 
			
		||||
                        "created_by": "MapComplete 0.16.6",
 | 
			
		||||
                        "host": "https://mapcomplete.osm.be/toerisme_vlaanderen.html",
 | 
			
		||||
                        "imagery": "osm",
 | 
			
		||||
                        "locale": "nl",
 | 
			
		||||
                        "source": "survey",
 | 
			
		||||
                        "source:node/-1":"note/1234",
 | 
			
		||||
                        "theme": "toerisme_vlaanderen",
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                let rewritten = cs.RewriteTagsOf(
 | 
			
		||||
                    [{
 | 
			
		||||
                       key: "newTag",
 | 
			
		||||
                       value: "newValue",
 | 
			
		||||
                       aggregate: false 
 | 
			
		||||
                    }],
 | 
			
		||||
                    new Map<string, string>(),
 | 
			
		||||
                    oldChangesetMeta)
 | 
			
		||||
                let d = ChangesetHandlerSpec.asDict(rewritten)
 | 
			
		||||
                T.equals(10, d.size)
 | 
			
		||||
                T.equals("5", d.get("answer"))
 | 
			
		||||
                T.equals("Adding data with #MapComplete for theme #toerisme_vlaanderen", d.get("comment"))
 | 
			
		||||
                T.equals("MapComplete 0.16.6", d.get("created_by"))
 | 
			
		||||
                T.equals("https://mapcomplete.osm.be/toerisme_vlaanderen.html", d.get("host"))
 | 
			
		||||
                T.equals("osm", d.get("imagery"))
 | 
			
		||||
                T.equals("survey", d.get("source"))
 | 
			
		||||
                T.equals("note/1234", d.get("source:node/-1"))
 | 
			
		||||
                T.equals("toerisme_vlaanderen", d.get("theme"))
 | 
			
		||||
                
 | 
			
		||||
                T.equals("newValue", d.get("newTag"))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                rewritten = cs.RewriteTagsOf(
 | 
			
		||||
                    [{
 | 
			
		||||
                        key: "answer",
 | 
			
		||||
                        value: "37",
 | 
			
		||||
                        aggregate: true
 | 
			
		||||
                    }],
 | 
			
		||||
                    new Map<string, string>(),
 | 
			
		||||
                    oldChangesetMeta)
 | 
			
		||||
                d = ChangesetHandlerSpec.asDict(rewritten)
 | 
			
		||||
                
 | 
			
		||||
                T.equals(9, d.size)
 | 
			
		||||
                T.equals("42", d.get("answer"))
 | 
			
		||||
                T.equals("Adding data with #MapComplete for theme #toerisme_vlaanderen", d.get("comment"))
 | 
			
		||||
                T.equals("MapComplete 0.16.6", d.get("created_by"))
 | 
			
		||||
                T.equals("https://mapcomplete.osm.be/toerisme_vlaanderen.html", d.get("host"))
 | 
			
		||||
                T.equals("osm", d.get("imagery"))
 | 
			
		||||
                T.equals("survey", d.get("source"))
 | 
			
		||||
                T.equals("note/1234", d.get("source:node/-1"))
 | 
			
		||||
                T.equals("toerisme_vlaanderen", d.get("theme"))
 | 
			
		||||
 | 
			
		||||
                rewritten = cs.RewriteTagsOf(
 | 
			
		||||
                    [],
 | 
			
		||||
                    new Map<string, string>([["node/-1", "node/42"]]),
 | 
			
		||||
                    oldChangesetMeta)
 | 
			
		||||
                d = ChangesetHandlerSpec.asDict(rewritten)
 | 
			
		||||
 | 
			
		||||
                T.equals(9, d.size)
 | 
			
		||||
                T.equals("5", d.get("answer"))
 | 
			
		||||
                T.equals("Adding data with #MapComplete for theme #toerisme_vlaanderen", d.get("comment"))
 | 
			
		||||
                T.equals("MapComplete 0.16.6", d.get("created_by"))
 | 
			
		||||
                T.equals("https://mapcomplete.osm.be/toerisme_vlaanderen.html", d.get("host"))
 | 
			
		||||
                T.equals("osm", d.get("imagery"))
 | 
			
		||||
                T.equals("survey", d.get("source"))
 | 
			
		||||
                T.equals("note/1234", d.get("source:node/42"))
 | 
			
		||||
                T.equals("toerisme_vlaanderen", d.get("theme"))
 | 
			
		||||
 | 
			
		||||
            },
 | 
			
		||||
            ],[
 | 
			
		||||
                "Test rewrite on special motivation", () => {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                    const cs = new ChangesetHandler(new UIEventSource<boolean>(true),
 | 
			
		||||
                        new OsmConnection({}),
 | 
			
		||||
                        new ElementStorage(),
 | 
			
		||||
                        new Changes(),
 | 
			
		||||
                        new UIEventSource(undefined)
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                    const oldChangesetMeta = {
 | 
			
		||||
                        "type": "changeset",
 | 
			
		||||
                        "id": 118443748,
 | 
			
		||||
                        "created_at": "2022-03-13T19:52:10Z",
 | 
			
		||||
                        "closed_at": "2022-03-13T20:54:35Z",
 | 
			
		||||
                        "open": false,
 | 
			
		||||
                        "user": "Pieter Vander Vennet",
 | 
			
		||||
                        "uid": 3818858,
 | 
			
		||||
                        "minlat": 51.0361902,
 | 
			
		||||
                        "minlon": 3.7092939,
 | 
			
		||||
                        "maxlat": 51.0364194,
 | 
			
		||||
                        "maxlon": 3.7099520,
 | 
			
		||||
                        "comments_count": 0,
 | 
			
		||||
                        "changes_count": 3,
 | 
			
		||||
                        "tags": {
 | 
			
		||||
                            "answer": "5",
 | 
			
		||||
                            "comment": "Adding data with #MapComplete for theme #toerisme_vlaanderen",
 | 
			
		||||
                            "created_by": "MapComplete 0.16.6",
 | 
			
		||||
                            "host": "https://mapcomplete.osm.be/toerisme_vlaanderen.html",
 | 
			
		||||
                            "imagery": "osm",
 | 
			
		||||
                            "locale": "nl",
 | 
			
		||||
                            "source": "survey",
 | 
			
		||||
                            "source:-1":"note/1234",
 | 
			
		||||
                            "theme": "toerisme_vlaanderen",
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            
 | 
			
		||||
                    const extraMetaTags : ChangesetTag[] = [
 | 
			
		||||
                        {
 | 
			
		||||
                            key: "created_by",
 | 
			
		||||
                            value:"mapcomplete"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            key: "source:node/-1",
 | 
			
		||||
                            value:"note/1234"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                    const changes = new Map<string, string>([["node/-1","node/42"]])
 | 
			
		||||
                    const hasSpecialMotivationChanges = ChangesetHandler.rewriteMetaTags(extraMetaTags, changes)
 | 
			
		||||
                    T.isTrue(hasSpecialMotivationChanges, "Special rewrite did not trigger")
 | 
			
		||||
                    // Rewritten inline by rewriteMetaTags
 | 
			
		||||
                    T.equals("source:node/42", extraMetaTags[1].key)
 | 
			
		||||
                    T.equals("note/1234", extraMetaTags[1].value)
 | 
			
		||||
                    T.equals("created_by", extraMetaTags[0].key)
 | 
			
		||||
                    T.equals("mapcomplete", extraMetaTags[0].value)
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
            ]
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -21,11 +21,16 @@ import ValidatedTextFieldTranslationsSpec from "./ValidatedTextFieldTranslations
 | 
			
		|||
import CreateCacheSpec from "./CreateCache.spec";
 | 
			
		||||
import CodeQualitySpec from "./CodeQuality.spec";
 | 
			
		||||
import ImportMultiPolygonSpec from "./ImportMultiPolygon.spec";
 | 
			
		||||
import {ChangesetHandler} from "../Logic/Osm/ChangesetHandler";
 | 
			
		||||
import ChangesetHandlerSpec from "./ChangesetHandler.spec";
 | 
			
		||||
import ChangesSpec from "./Changes.spec";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async function main() {
 | 
			
		||||
 | 
			
		||||
    const allTests: T[] = [
 | 
			
		||||
        new ChangesSpec(),
 | 
			
		||||
        new ChangesetHandlerSpec(),
 | 
			
		||||
        new OsmObjectSpec(),
 | 
			
		||||
        new TagSpec(),
 | 
			
		||||
        new ImageAttributionSpec(),
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +50,7 @@ async function main() {
 | 
			
		|||
        new ValidatedTextFieldTranslationsSpec(),
 | 
			
		||||
        new CreateCacheSpec(),
 | 
			
		||||
        new CodeQualitySpec(),
 | 
			
		||||
        new ImportMultiPolygonSpec()
 | 
			
		||||
        new ImportMultiPolygonSpec(),
 | 
			
		||||
    ]
 | 
			
		||||
    ScriptUtils.fixUtils();
 | 
			
		||||
    const realDownloadFunc = Utils.externalDownloadFunction;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue