diff --git a/assets/themes/hailhydrant/Twemoji12_1f692.svg b/assets/themes/hailhydrant/Twemoji12_1f692.svg new file mode 100644 index 0000000..711c996 --- /dev/null +++ b/assets/themes/hailhydrant/Twemoji12_1f692.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/hailhydrant/Twemoji12_1f9ef.svg b/assets/themes/hailhydrant/Twemoji12_1f9ef.svg new file mode 100644 index 0000000..e8b17ac --- /dev/null +++ b/assets/themes/hailhydrant/Twemoji12_1f9ef.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/hailhydrant/Twemoji12_26d1.svg b/assets/themes/hailhydrant/Twemoji12_26d1.svg new file mode 100644 index 0000000..e8457ae --- /dev/null +++ b/assets/themes/hailhydrant/Twemoji12_26d1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/hailhydrant/hailhydrant.json b/assets/themes/hailhydrant/hailhydrant.json new file mode 100644 index 0000000..ca17c2b --- /dev/null +++ b/assets/themes/hailhydrant/hailhydrant.json @@ -0,0 +1,520 @@ +{ + "id": "hailhydrant", + "title": { + "en": "Hydrants, Extinguishers, Fire stations, and Rescue stations." + }, + "shortDescription": { + "en": "Map to show hydrants, extinguishers, fire stations, and rescue stations." + }, + "description": { + "en": "On this map you can find and update hydrants, fire stations, rescue stations, and extinguishers in your favorite neighborhoods. \n\nYou can track your precise location (mobile only) and select layers that are relevant for you in the bottom left corner. You can also use this tool to add or edit pins (points of interest) to the map and provide additional details by answering available questions. \n\nAll changes you make will automatically be saved in the global database of OpenStreetMap and can be freely re-used by others." + }, + "language": [ + "en" + ], + "maintainer": "", + "icon": "./assets/themes/hailhydrant/logo.svg", + "version": "0", + "startLat": 13.67801, + "startLon": 121.6625, + "startZoom": 6, + "widenFactor": 0.05, + "socialImage": "", + "layers": [ + { + "id": "hydrants", + "name": { + "en": "Map of hydrants" + }, + "minzoom": 14, + "source": { + "osmTags": { + "and": [ + "emergency=fire_hydrant" + ] + } + }, + "title": { + "render": { + "en": "Hydrant" + } + }, + "description": { + "en": "Map layer to show fire hydrants." + }, + "tagRenderings": [ + "images", + { + "question": { + "en": "What color is the hydrant?" + }, + "render": { + "en": "The hydrant color is {colour}" + }, + "freeform": { + "key": "colour" + }, + "mappings": [ + { + "if": { + "and": [ + "colour=yellow" + ] + }, + "then": { + "en": "The hydrant color is yellow." + } + }, + { + "if": { + "and": [ + "colour=red" + ] + }, + "then": { + "en": "The hydrant color is red." + } + } + ] + }, + { + "question": { + "en": "What type of hydrant is it?" + }, + "freeform": { + "key": "fire_hydrant:type" + }, + "render": { + "en": " Hydrant type: {fire_hydrant:type}" + }, + "mappings": [ + { + "if": { + "and": [ + "fire_hydrant:type=pillar" + ] + }, + "then": { + "en": " Pillar type." + } + }, + { + "if": { + "and": [ + "fire_hydrant:type=pipe" + ] + }, + "then": { + "en": " Pipe type." + } + }, + { + "if": { + "and": [ + "fire_hydrant:type=wall" + ] + }, + "then": { + "en": " Wall type." + } + }, + { + "if": { + "and": [ + "fire_hydrant:type=underground" + ] + }, + "then": { + "en": " Underground type." + } + } + ] + }, + { + "question": { + "en": "Update the lifecycle status of the hydrant." + }, + "render": { + "en": "Lifecycle status" + }, + "freeform": { + "key": "disused:emergency" + }, + "mappings": [ + { + "if": { + "and": [ + "emergency=fire_hydrant" + ] + }, + "then": { + "en": "The hydrant is (fully or partially) working." + } + }, + { + "if": { + "and": [ + "disused:emergency=fire_hydrant", + "emergency=" + ] + }, + "then": { + "en": "The hydrant is unavailable." + } + }, + { + "if": { + "and": [ + "removed:emergency=fire_hydrant", + "emergency=" + ] + }, + "then": { + "en": "The hydrant has been removed." + } + } + ] + } + ], + "hideUnderlayingFeaturesMinPercentage": 0, + "icon": { + "render": "./assets/themes/hailhydrant/hydrant.svg" + }, + "width": { + "render": "8" + }, + "iconSize": { + "render": "20,20,center" + }, + "color": { + "render": "#00f" + }, + "presets": [ + { + "tags": [ + "emergency=fire_hydrant" + ], + "title": { + "en": "Fire hydrant" + }, + "description": { + "en": "A hydrant is a connection point where firefighters can tap water. It might be located underground." + } + } + ], + "wayHandling": 2 + }, + { + "id": "extinguisher", + "name": { + "en": "Map of fire extinguishers." + }, + "minzoom": 14, + "source": { + "osmTags": { + "and": [ + "emergency=fire_extinguisher" + ] + } + }, + "title": { + "render": { + "en": "Extinguishers" + } + }, + "description": { + "en": "Map layer to show fire hydrants." + }, + "tagRenderings": [ + "images", + { + "render": { + "en": "Location: {location}" + }, + "question": { + "en": "Where is it positioned?" + }, + "mappings": [ + { + "if": { + "and": [ + "location=indoor" + ] + }, + "then": { + "en": "Found indoors." + } + }, + { + "if": { + "and": [ + "location=outdoor" + ] + }, + "then": { + "en": "Found outdoors." + } + } + ], + "freeform": { + "key": "location" + } + } + ], + "hideUnderlayingFeaturesMinPercentage": 0, + "icon": { + "render": "./assets/themes/hailhydrant/Twemoji12_1f9ef.svg" + }, + "width": { + "render": "8" + }, + "iconSize": { + "render": "20,20,center" + }, + "color": { + "render": "#00f" + }, + "presets": [ + { + "tags": [ + "emergency=fire_extinguisher" + ], + "title": { + "en": "Fire extinguisher" + }, + "description": { + "en": "A fire extinguisher is a small, portable device used to stop a fire" + } + } + ], + "wayHandling": 1 + }, + { + "id": "fire_stations", + "name": { + "en": "Map of fire stations" + }, + "minzoom": 12, + "source": { + "osmTags": { + "and": [ + "amenity=fire_station" + ] + } + }, + "wayHandling": 2, + "title": { + "render": { + "en": "Fire Station" + } + }, + "description": { + "en": "Map layer to show fire stations." + }, + "tagRenderings": [ + "images", + { + "freeform": { + "key": "name" + }, + "question": { + "en": "What is the name of this station?" + }, + "render": { + "en": "This station is called {name}." + } + }, + { + "freeform": { + "key": "addr:street" + }, + "question": { + "en": " What is the street name where the station located?" + }, + "render": { + "en": "This station is along a highway called {addr:street}." + } + }, + { + "question": { + "en": "Where is the station located? (e.g. name of neighborhood, villlage, or town)" + }, + "freeform": { + "key": "addr:place" + }, + "render": { + "en": "Th isstation is to be found within {addr:place}." + } + }, + { + "question": { + "en": "What agency operates this station?" + }, + "render": { + "en": "This station is operated by {operator}." + }, + "freeform": { + "key": "operator" + }, + "mappings": [ + { + "if": { + "and": [ + "operator=Bureau of Fire Protection", + "operator:type=government" + ] + }, + "then": { + "en": "Bureau of Fire Protection" + } + } + ] + }, + { + "question": { + "en": "How is the station operator classified??" + }, + "render": { + "en": "The operator is a(n) {operator:type} entity." + }, + "freeform": { + "key": "operator:type" + }, + "mappings": [ + { + "if": { + "and": [ + "operator:type=government" + ] + }, + "then": { + "en": "The station is operated by the government." + } + }, + { + "if": { + "and": [ + "operator:type=community" + ] + }, + "then": { + "en": "The station is operated by a community-based, or informal organization." + } + }, + { + "if": { + "and": [ + "operator:type=ngo" + ] + }, + "then": { + "en": "The station is operated by a formal group of volunteers." + } + }, + { + "if": { + "and": [ + "operator:type=private" + ] + }, + "then": { + "en": "The station is privately operated." + } + } + ] + } + ], + "hideUnderlayingFeaturesMinPercentage": 0, + "icon": { + "render": "./assets/themes/hailhydrant/Twemoji12_1f692.svg" + }, + "width": { + "render": "1" + }, + "iconSize": { + "render": "35,35,center" + }, + "color": { + "render": "#c22" + }, + "presets": [ + { + "tags": [ + "amenity=fire_station" + ], + "title": { + "en": "Fire station" + }, + "description": { + "en": "A fire station is a place where the fire trucks and firefighters are located when not in operation." + } + } + ] + }, + { + "id": "rescuestation", + "name": { + "en": "Map of rescue stations" + }, + "minzoom": 12, + "source": { + "osmTags": { + "and": [ + "amenity=rescue_station" + ] + } + }, + "title": { + "render": { + "en": "Rescue Station" + } + }, + "description": { + "en": "Map layer to show rescue stations." + }, + "tagRenderings": [ + "images", + { + "question": { + "en": "What is this entity called?" + }, + "freeform": { + "key": "name" + }, + "render": { + "en": "This entity is called {name}." + } + } + ], + "hideUnderlayingFeaturesMinPercentage": 0, + "icon": { + "render": "./assets/themes/hailhydrant/Twemoji12_26d1.svg" + }, + "width": { + "render": "1" + }, + "iconSize": { + "render": "35,35,center" + }, + "color": { + "render": "#00f" + }, + "presets-disabled": [ + { + "tags": [ + "amenity=rescue_station" + ], + "title": { + "en": "Rescue station" + }, + "description": { + "en": "Add a rescue or emergency service station to the map" + } + } + ], + "wayHandling": 2 + } + ], + "defaultBackgroundId": "HDM_HOT" +} + diff --git a/assets/themes/hailhydrant/hydrant.svg b/assets/themes/hailhydrant/hydrant.svg new file mode 100644 index 0000000..0dbda22 --- /dev/null +++ b/assets/themes/hailhydrant/hydrant.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/themes/hailhydrant/hydrant_pillar.svg b/assets/themes/hailhydrant/hydrant_pillar.svg new file mode 100644 index 0000000..27ef663 --- /dev/null +++ b/assets/themes/hailhydrant/hydrant_pillar.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/themes/hailhydrant/hydrant_underground.svg b/assets/themes/hailhydrant/hydrant_underground.svg new file mode 100644 index 0000000..f7c0f3d --- /dev/null +++ b/assets/themes/hailhydrant/hydrant_underground.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/themes/hailhydrant/hydrant_unknown.svg b/assets/themes/hailhydrant/hydrant_unknown.svg new file mode 100644 index 0000000..10b31cd --- /dev/null +++ b/assets/themes/hailhydrant/hydrant_unknown.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/themes/hailhydrant/license_info.json b/assets/themes/hailhydrant/license_info.json new file mode 100644 index 0000000..9a4186f --- /dev/null +++ b/assets/themes/hailhydrant/license_info.json @@ -0,0 +1,98 @@ +[ + { + "authors": [ + "http://jaanos.deviantart.com/" + ], + "path": "hydrant.svg", + "license": "GPL", + "sources": [ + "https://commons.wikimedia.org/wiki/File:Hydrant.svg" + ] + }, + { + "authors": [ + "Twemoji Project" + ], + "path": "Twemoji12_1f9ef.svg", + "license": "CC-BY 4.0", + "sources": [ + "https://upload.wikimedia.org/wikipedia/commons/9/9b/Twemoji12_1f9ef.svg", + "https://twemoji.twitter.com/" + ] + }, + { + "path": "hydrant_pillar.svg", + "license": "CC-BY-SA 4.0", + "authors": [ + "M!dgard" + ], + "sources": [ + "https://www.openstreetmap.org/user/M!dgard", + "https://mapcomplete.braindeaddev.com/assets/layers/fire/hydrant_underground.svg" + ] + }, + { + "path": "hydrant_unknown.svg", + "license": "CC-BY-SA 4.0", + "authors": [ + "M!dgard" + ], + "sources": [ + "https://www.openstreetmap.org/user/M!dgard", + "https://mapcomplete.braindeaddev.com/assets/layers/fire/hydrant_underground.svg" + ] + }, + { + "path": "hydrant_underground.svg", + "license": "CC-BY-SA 4.0", + "authors": [ + "M!dgard" + ], + "sources": [ + "https://www.openstreetmap.org/user/M!dgard", + "https://mapcomplete.braindeaddev.com/assets/layers/fire/hydrant_underground.svg" + ] + }, + { + "path": "hydrant.svg", + "license": "CC-BY-SA 4.0", + "authors": [ + "GOwin" + ], + "sources": [ + "https://raw.githubusercontent.com/mapamore/MapComplete/master/assets/themes/hailhydrant/hydrant.svg" + ] + }, + { + "path": "Twemoji12_1f692.svg", + "license": "CC-BY 4.0", + "authors": [ + "Twemoji Project" + ], + "sources": [ + "https://upload.wikimedia.org/wikipedia/commons/1/19/Twemoji12_1f692.svg", + "https://twemoji.twitter.com/" + ] + }, + { + "path": "Twemoji12_26d1.svg", + "license": "CC-BY 4.0", + "authors": [ + "Twemoji Project" + ], + "sources": [ + "https://upload.wikimedia.org/wikipedia/commons/e/eb/Twemoji12_26d1.svg", + "https://twemoji.twitter.com/" + ] + }, + { + "authors": [ + "Erwin Olario" + ], + "path": "logo.svg", + "license": "CC-BY-SA 4.0", + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Hailhydrant-logo.svg" + ] + } +] \ No newline at end of file diff --git a/assets/themes/hailhydrant/logo.svg b/assets/themes/hailhydrant/logo.svg new file mode 100644 index 0000000..d491480 --- /dev/null +++ b/assets/themes/hailhydrant/logo.svg @@ -0,0 +1,53 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/generated.license_info.json b/generated.license_info.json new file mode 100644 index 0000000..83e959f --- /dev/null +++ b/generated.license_info.json @@ -0,0 +1,58 @@ +[ + { + "path": "hydrant_pillar.svg", + "license": "", + "authors": [], + "sources": [ + "https://mapcomplete.braindeaddev.com/assets/layers/fire/hydrant_pillar.svg" + ] + }, + { + "path": "hydrant_unknown.svg", + "license": "", + "authors": [], + "sources": [ + "https://mapcomplete.braindeaddev.com/assets/layers/fire/hydrant_unknown.svg" + ] + }, + { + "path": "hydrant_underground.svg", + "license": "", + "authors": [], + "sources": [ + "https://mapcomplete.braindeaddev.com/assets/layers/fire/hydrant_underground.svg" + ] + }, + { + "path": "Hydrant_02.svg", + "license": "", + "authors": [], + "sources": [ + "https://upload.wikimedia.org/wikipedia/commons/6/66/Hydrant_02.svg" + ] + }, + { + "path": "MUTCD_RS-090.svg", + "license": "", + "authors": [], + "sources": [ + "https://upload.wikimedia.org/wikipedia/commons/e/e8/MUTCD_RS-090.svg" + ] + }, + { + "path": "British_Columbia_W-318-L.svg", + "license": "", + "authors": [], + "sources": [ + "https://upload.wikimedia.org/wikipedia/commons/8/84/British_Columbia_W-318-L.svg" + ] + }, + { + "path": "Emojione_1F6A8.svg", + "license": "", + "authors": [], + "sources": [ + "https://upload.wikimedia.org/wikipedia/commons/1/1e/Emojione_1F6A8.svg" + ] + } +] \ No newline at end of file diff --git a/package.json b/package.json index 158f759..476e1a4 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "main": "index.js", "scripts": { "increase-memory": "export NODE_OPTIONS=--max_old_space_size=4096", - "start": "ts-node scripts/generateLayerOverview.ts && npm run increase-memory && parcel *.html UI/** Logic/** assets/** assets/**/** assets/**/**/** vendor/* vendor/*/*", + "start": "ts-node scripts/generateLayerOverview.ts --no-fail && npm run increase-memory && parcel *.html UI/** Logic/** assets/** assets/**/** assets/**/**/** vendor/* vendor/*/*", "test": "ts-node test/Tag.spec.ts && ts-node test/TagQuestion.spec.ts && ts-node test/ImageSearcher.spec.ts && ts-node test/ImageAttribution.spec.ts", "generate:editor-layer-index": "cd assets/ && wget https://osmlab.github.io/editor-layer-index/imagery.geojson --output-document=editor-layer-index.json", "generate:images": "ts-node scripts/generateIncludedImages.ts", diff --git a/scripts/fixTheme.ts b/scripts/fixTheme.ts new file mode 100644 index 0000000..b3d0404 --- /dev/null +++ b/scripts/fixTheme.ts @@ -0,0 +1,70 @@ + +/* + * This script attempt to automatically fix some basic issues when a theme from the custom generator is loaded + */ +import {Utils} from "../Utils" +Utils.runningFromConsole = true; +import {readFileSync, writeFileSync} from "fs"; +import {LayoutConfigJson} from "../Customizations/JSON/LayoutConfigJson"; +import {Layer} from "leaflet"; +import LayerConfig from "../Customizations/JSON/LayerConfig"; +import SmallLicense from "../Models/smallLicense"; + +if(process.argv.length == 2){ + console.log("USAGE: ts-node scripts/fixTheme ") + throw "No path specified" +} + +const path = process.argv[2] +const dir = path.substring(0, path.lastIndexOf("/")) + +console.log("Fixing up ", path) + +const themeConfigJson : LayoutConfigJson = JSON.parse(readFileSync(path, "UTF8")) + +const linuxHints = [] +const licenses : SmallLicense[] = [] + +const replacements: {source: string, destination: string}[] = [] + +for (const layerConfigJson of themeConfigJson.layers) { + if(typeof (layerConfigJson) === "string"){ + continue; + } + if(layerConfigJson["overpassTags"] !== undefined){ + const tags = layerConfigJson["overpassTags"]; + layerConfigJson["overpassTags"] = undefined; + layerConfigJson["source"] = { osmTags : tags} + } + // @ts-ignore + const layerConfig = new LayerConfig(layerConfigJson, true) + const images : string[] = Array.from(layerConfig.ExtractImages()) + const remoteImages = images.filter(img => img.startsWith("http")) + for (const remoteImage of remoteImages) { + linuxHints.push("wget " + remoteImage) + const imgPath = remoteImage.substring(remoteImage.lastIndexOf("/") + 1) + licenses.push({ + path: imgPath, + license: "", + authors: [], + sources: [remoteImage] + }) + replacements.push({source: remoteImage, destination: `${dir}/${imgPath}`}) + } +} + +let fixedThemeJson = JSON.stringify(themeConfigJson, null , " ") +for (const replacement of replacements) { + fixedThemeJson = fixedThemeJson.replace(new RegExp(replacement.source, "g"), replacement.destination) +} + +const fixScriptPath = dir + "/fix_script_"+path.replace(/\//g,"_")+".sh" +writeFileSync(dir + "/generated.license_info.json", JSON.stringify(licenses, null, " ")) +writeFileSync(fixScriptPath, linuxHints.join("\n")) +writeFileSync(path+".autofixed.json", fixedThemeJson) + +console.log(`IMPORTANT: + 1) run ${fixScriptPath} + 2) Copy generated.license_info.json over into license_info.json and add the missing attributions and authors + 3) Verify ${path}.autofixed.json as theme, and rename it to ${path} + 4) Delete the fix script and other unneeded files`) \ No newline at end of file diff --git a/scripts/generateLayerOverview.ts b/scripts/generateLayerOverview.ts index 6443266..77d26c2 100644 --- a/scripts/generateLayerOverview.ts +++ b/scripts/generateLayerOverview.ts @@ -51,8 +51,6 @@ for (const i in licenses) { } const knownPaths = new Set(licensePaths) -const linuxHints = [] - function validateLayer(layerJson: LayerConfigJson, context?: string): string[] { let errorCount = []; if (layerJson["overpassTags"] !== undefined) { @@ -65,9 +63,7 @@ function validateLayer(layerJson: LayerConfigJson, context?: string): string[] { for (const remoteImage of remoteImages) { errorCount.push("Found a remote image: " + remoteImage + " in layer " + layer.id + ", please download it.") const path = remoteImage.substring(remoteImage.lastIndexOf("/") + 1) - linuxHints.push("wget " + remoteImage) - linuxHints.push(`echo '{"path":"${path}", "license": "", "authors": [ " ${path}.license_info.json`) - } + } for (const image of images) { if (!knownPaths.has(image)) { const ctx = context === undefined ? "" : ` in a layer defined in the theme ${context}` @@ -129,7 +125,6 @@ if (layerErrorCount.length + themeErrorCount.length == 0) { console.log(errors) const msg = (`Found ${layerErrorCount.length} errors in the layers; ${themeErrorCount.length} errors in the themes`) console.log(msg) - console.log(linuxHints.join("\n")) if (process.argv.indexOf("--report") >= 0) { console.log("Writing report!") writeFileSync("layer_report.txt", errors) diff --git a/scripts/generateLicenseInfo.ts b/scripts/generateLicenseInfo.ts index 05a00f7..f7c0723 100644 --- a/scripts/generateLicenseInfo.ts +++ b/scripts/generateLicenseInfo.ts @@ -193,17 +193,18 @@ writeFileSync("./assets/generated/license_info.json", JSON.stringify(licenseInfo const artwork = contents.filter(pth => pth.match(/(.svg|.png|.jpg)$/i) != null) const missingLicenses = missingLicenseInfos(licenseInfos, artwork) - +const invalidLicenses = licenseInfos.filter(l => (l.license ?? "") === "").map(l => `License for artwork ${l.path} is empty string or undefined`) if (process.argv.indexOf("--prompt") >= 0 || process.argv.indexOf("--query") >= 0) { queryMissingLicenses(missingLicenses) } if (missingLicenses.length > 0) { - const msg = `There are ${missingLicenses.length} licenses missing.` + const msg = `There are ${missingLicenses.length} licenses missing and ${invalidLicenses.length} invalid licenses.` + console.log( missingLicenses.concat(invalidLicenses).join("\n")) console.error(msg) if (process.argv.indexOf("--report") >= 0) { console.log("Writing report!") - writeFileSync("missing_licenses.txt", missingLicenses.join("\n")) + writeFileSync("missing_licenses.txt", missingLicenses.concat(invalidLicenses).join("\n")) } if (process.argv.indexOf("--no-fail") < 0) { throw msg