forked from MapComplete/MapComplete
		
	Enable more privacy for some themes and layers
This commit is contained in:
		
							parent
							
								
									484adf1ee1
								
							
						
					
					
						commit
						91b836bf66
					
				
					 15 changed files with 59 additions and 16 deletions
				
			
		|  | @ -28,6 +28,7 @@ | |||
|     "pt_BR": "Completaremos os dados das características de publicidade com referência, operador e iluminação", | ||||
|     "it": "Completeremo i dati da caratteristiche pubblicitarie, con referenza, operatore e illuminazione" | ||||
|   }, | ||||
|   "enableMorePrivacy": true, | ||||
|   "source": { | ||||
|     "osmTags": { | ||||
|       "and": [ | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ | |||
|   "source": { | ||||
|     "osmTags": "amenity=brothel" | ||||
|   }, | ||||
|   "enableMorePrivacy": true, | ||||
|   "minzoom": 6, | ||||
|   "title": { | ||||
|     "render": { | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ | |||
|     "en": "A love hotel is a type of short-stay hotel found around the world operated primarily for the purpose of allowing guests privacy for sexual activities", | ||||
|     "de": "Ein Love Hotel ist eine Art Kurzzeithotel, das in erster Linie zu dem Zweck betrieben wird, den Gästen Privatsphäre für sexuelle Aktivitäten zu bieten" | ||||
|   }, | ||||
|   "enableMorePrivacy": true, | ||||
|   "source": { | ||||
|     "osmTags": "amenity=love_hotel" | ||||
|   }, | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ | |||
|     "en": "A venue where erotic dance, striptease, or lap dances are performed commercially. ", | ||||
|     "de": "Ein Ort, an dem erotische Tanz-, Striptease- oder Lapdances kommerziell durchgeführt werden. " | ||||
|   }, | ||||
|   "enableMorePrivacy": true, | ||||
|   "source": { | ||||
|     "osmTags": "amenity=stripclub" | ||||
|   }, | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ | |||
|     "cs": "Tato vrstva zobrazuje sledovací kamery a umožňuje přispěvateli aktualizovat informace a přidávat nové kamery", | ||||
|     "sl": "Ta sloj prikazuje nadzorne kamere in urednikom omogoča posodabljanje informacij obstoječih in dodajanje novih kamer" | ||||
|   }, | ||||
|   "enableMorePrivacy": true, | ||||
|   "source": { | ||||
|     "osmTags": { | ||||
|       "and": [ | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ | |||
|   }, | ||||
|   "icon": "./assets/layers/stripclub/stripclub.svg", | ||||
|   "hideFromOverview": true, | ||||
|   "enableMorePrivacy": true, | ||||
|   "layers": [ | ||||
|     "brothel", | ||||
|     "stripclub", | ||||
|  |  | |||
|  | @ -52,6 +52,7 @@ | |||
|   }, | ||||
|   "icon": "./assets/themes/surveillance/logo.svg", | ||||
|   "defaultBackgroundId": "maptiler.carto", | ||||
|   "enableMorePrivacy": true, | ||||
|   "layers": [ | ||||
|     "surveillance_camera", | ||||
|     { | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ import Title from "../../UI/Base/Title" | |||
| import Table from "../../UI/Base/Table" | ||||
| import ChangeLocationAction from "./Actions/ChangeLocationAction" | ||||
| import ChangeTagAction from "./Actions/ChangeTagAction" | ||||
| import FeatureSwitchState from "../State/FeatureSwitchState" | ||||
| 
 | ||||
| /** | ||||
|  * Handles all changes made to OSM. | ||||
|  | @ -28,7 +29,7 @@ export class Changes { | |||
|     public readonly pendingChanges: UIEventSource<ChangeDescription[]> = | ||||
|         LocalStorageSource.GetParsed<ChangeDescription[]>("pending-changes", []) | ||||
|     public readonly allChanges = new UIEventSource<ChangeDescription[]>(undefined) | ||||
|     public readonly state: { allElements?: IndexedFeatureSource; osmConnection: OsmConnection } | ||||
|     public readonly state: { allElements?: IndexedFeatureSource; osmConnection: OsmConnection, featureSwitches?: FeatureSwitchState } | ||||
|     public readonly extraComment: UIEventSource<string> = new UIEventSource(undefined) | ||||
|     public readonly backend: string | ||||
|     public readonly isUploading = new UIEventSource(false) | ||||
|  | @ -45,7 +46,8 @@ export class Changes { | |||
|             allElements?: IndexedFeatureSource | ||||
|             featurePropertiesStore?: FeaturePropertiesStore | ||||
|             osmConnection: OsmConnection | ||||
|             historicalUserLocations?: FeatureSource | ||||
|             historicalUserLocations?: FeatureSource, | ||||
|             featureSwitches?: FeatureSwitchState | ||||
|         }, | ||||
|         leftRightSensitive: boolean = false | ||||
|     ) { | ||||
|  | @ -431,6 +433,9 @@ export class Changes { | |||
|             // Probably irrelevant, such as a new helper node
 | ||||
|             return | ||||
|         } | ||||
|         if(this.state.featureSwitches.featureSwitchMorePrivacy?.data){ | ||||
|             return | ||||
|         } | ||||
| 
 | ||||
|         const now = new Date() | ||||
|         const recentLocationPoints = locations | ||||
|  |  | |||
|  | @ -6,14 +6,6 @@ import Constants from "../../Models/Constants" | |||
| import { Changes } from "./Changes" | ||||
| import { Utils } from "../../Utils" | ||||
| import FeaturePropertiesStore from "../FeatureSource/Actors/FeaturePropertiesStore" | ||||
| import ChangeLocationAction from "./Actions/ChangeLocationAction" | ||||
| import ChangeTagAction from "./Actions/ChangeTagAction" | ||||
| import DeleteAction from "./Actions/DeleteAction" | ||||
| import LinkImageAction from "./Actions/LinkImageAction" | ||||
| import OsmChangeAction from "./Actions/OsmChangeAction" | ||||
| import RelationSplitHandler from "./Actions/RelationSplitHandler" | ||||
| import ReplaceGeometryAction from "./Actions/ReplaceGeometryAction" | ||||
| import SplitAction from "./Actions/SplitAction" | ||||
| 
 | ||||
| export interface ChangesetTag { | ||||
|     key: string | ||||
|  | @ -232,7 +224,7 @@ export class ChangesetHandler { | |||
|             if (newMetaTag === undefined) { | ||||
|                 extraMetaTags.push({ | ||||
|                     key: key, | ||||
|                     value: oldCsTags[key], | ||||
|                     value: oldCsTags[key] | ||||
|                 }) | ||||
|                 continue | ||||
|             } | ||||
|  | @ -361,21 +353,22 @@ export class ChangesetHandler { | |||
|     } | ||||
| 
 | ||||
|     private defaultChangesetTags(): ChangesetTag[] { | ||||
|         const usedGps = this.changes.state["currentUserLocation"]?.features?.data?.length > 0 | ||||
|         const hasMorePrivacy = !!this.changes.state?.featureSwitches?.featureSwitchMorePrivacy?.data | ||||
|         const setSourceAsSurvey = !hasMorePrivacy && usedGps | ||||
|         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, | ||||
|                 setSourceAsSurvey                    ? "survey"                    : undefined | ||||
|             ], | ||||
|             ["imagery", this.changes.state["backgroundLayer"]?.data?.id], | ||||
|             ["imagery", this.changes.state["backgroundLayer"]?.data?.id] | ||||
|         ].map(([key, value]) => ({ | ||||
|             key, | ||||
|             value, | ||||
|             aggregate: false, | ||||
|             aggregate: false | ||||
|         })) | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -63,6 +63,7 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches { | |||
|     public readonly overpassMaxZoom: UIEventSource<number> | ||||
|     public readonly osmApiTileSize: UIEventSource<number> | ||||
|     public readonly backgroundLayerId: UIEventSource<string> | ||||
|     public readonly featureSwitchMorePrivacy: UIEventSource<boolean> | ||||
| 
 | ||||
|     public constructor(layoutToUse?: LayoutConfig) { | ||||
|         super() | ||||
|  | @ -164,6 +165,14 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches { | |||
|             "If true, shows some extra debugging help such as all the available tags on every object" | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
|         this.featureSwitchMorePrivacy = QueryParameters.GetBooleanQueryParameter( | ||||
|             "moreprivacy", | ||||
|             layoutToUse.enableMorePrivacy, | ||||
|             "If true, the location distance indication will not be written to the changeset and other privacy enhancing measures might be taken." | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
|         this.overpassUrl = QueryParameters.GetQueryParameter( | ||||
|             "overpassUrl", | ||||
|             (layoutToUse?.overpassUrl ?? Constants.defaultOverpassUrls).join(","), | ||||
|  |  | |||
|  | @ -554,4 +554,15 @@ export interface LayerConfigJson { | |||
|      * group: hidden | ||||
|      */ | ||||
|     fullNodeDatabase?: boolean | ||||
| 
 | ||||
|     /** | ||||
|      * question: Should a theme using this layer leak some location info when making changes? | ||||
|      * | ||||
|      * When a changeset is made, a 'distance to object'-class is written to the changeset. | ||||
|      * For some particular themes and layers, this might leak too much information, and we want to obfuscate this | ||||
|      * | ||||
|      * ifunset: Write 'change_within_x_m' as usual and if GPS is enabled | ||||
|      * iftrue: Do not write 'change_within_x_m' and do not indicate that this was done by survey | ||||
|      */ | ||||
|     enableMorePrivacy: boolean | ||||
| } | ||||
|  |  | |||
|  | @ -439,4 +439,16 @@ export interface LayoutConfigJson { | |||
|      * group: hidden | ||||
|      */ | ||||
|     enableNodeDatabase?: boolean | ||||
| 
 | ||||
|     /** | ||||
|      * question: Should this theme leak some location info when making changes? | ||||
|      * | ||||
|      * When a changeset is made, a 'distance to object'-class is written to the changeset. | ||||
|      * For some particular themes and layers, this might leak too much information, and we want to obfuscate this | ||||
|      * | ||||
|      * ifunset: Write 'change_within_x_m' as usual and if GPS is enabled | ||||
|      * iftrue: Do not write 'change_within_x_m' and do not indicate that this was done by survey | ||||
|      */ | ||||
|     enableMorePrivacy: boolean | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -67,6 +67,7 @@ export default class LayerConfig extends WithContextLoader { | |||
| 
 | ||||
|     public readonly _needsFullNodeDatabase: boolean | ||||
|     public readonly popupInFloatover: boolean | string | ||||
|     public readonly enableMorePrivacy: boolean | ||||
| 
 | ||||
|     constructor(json: LayerConfigJson, context?: string, official: boolean = true) { | ||||
|         context = context + "." + json.id | ||||
|  | @ -149,6 +150,7 @@ export default class LayerConfig extends WithContextLoader { | |||
|         this.shownByDefault = json.shownByDefault ?? true | ||||
|         this.doCount = json.isCounted ?? this.shownByDefault ?? true | ||||
|         this.forceLoad = json.forceLoad ?? false | ||||
|         this.enableMorePrivacy = json.enableMorePrivacy ?? false | ||||
|         if (json.presets === null) json.presets = undefined | ||||
|         if (json.presets !== undefined && json.presets?.map === undefined) { | ||||
|             throw "Presets should be a list of items (at " + context + ")" | ||||
|  |  | |||
|  | @ -63,6 +63,8 @@ export default class LayoutConfig implements LayoutInformation { | |||
|     public readonly enableExportButton: boolean | ||||
|     public readonly enablePdfDownload: boolean | ||||
|     public readonly enableTerrain: boolean | ||||
|     public readonly enableMorePrivacy: boolean | ||||
| 
 | ||||
| 
 | ||||
|     public readonly customCss?: string | ||||
| 
 | ||||
|  | @ -204,6 +206,7 @@ export default class LayoutConfig implements LayoutInformation { | |||
|         this.overpassTimeout = json.overpassTimeout ?? 30 | ||||
|         this.overpassMaxZoom = json.overpassMaxZoom ?? 16 | ||||
|         this.osmApiTileSize = json.osmApiTileSize ?? this.overpassMaxZoom + 1 | ||||
|         this.enableMorePrivacy = json.enableMorePrivacy || json.layers.some(l => (<LayerConfigJson> l).enableMorePrivacy) | ||||
| 
 | ||||
|         this.layersDict = new Map<string, LayerConfig>() | ||||
|         for (const layer of this.layers) { | ||||
|  |  | |||
|  | @ -265,6 +265,7 @@ export default class ThemeViewState implements SpecialVisualizationState { | |||
|                     featurePropertiesStore: this.featureProperties, | ||||
|                     osmConnection: this.osmConnection, | ||||
|                     historicalUserLocations: this.geolocation.historicalUserLocations, | ||||
|                     featureSwitches: this.featureSwitches | ||||
|                 }, | ||||
|                 layout?.isLeftRightSensitive() ?? false | ||||
|             ) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue