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", |     "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" |     "it": "Completeremo i dati da caratteristiche pubblicitarie, con referenza, operatore e illuminazione" | ||||||
|   }, |   }, | ||||||
|  |   "enableMorePrivacy": true, | ||||||
|   "source": { |   "source": { | ||||||
|     "osmTags": { |     "osmTags": { | ||||||
|       "and": [ |       "and": [ | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ | ||||||
|   "source": { |   "source": { | ||||||
|     "osmTags": "amenity=brothel" |     "osmTags": "amenity=brothel" | ||||||
|   }, |   }, | ||||||
|  |   "enableMorePrivacy": true, | ||||||
|   "minzoom": 6, |   "minzoom": 6, | ||||||
|   "title": { |   "title": { | ||||||
|     "render": { |     "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", |     "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" |     "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": { |   "source": { | ||||||
|     "osmTags": "amenity=love_hotel" |     "osmTags": "amenity=love_hotel" | ||||||
|   }, |   }, | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ | ||||||
|     "en": "A venue where erotic dance, striptease, or lap dances are performed commercially. ", |     "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. " |     "de": "Ein Ort, an dem erotische Tanz-, Striptease- oder Lapdances kommerziell durchgeführt werden. " | ||||||
|   }, |   }, | ||||||
|  |   "enableMorePrivacy": true, | ||||||
|   "source": { |   "source": { | ||||||
|     "osmTags": "amenity=stripclub" |     "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", |     "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" |     "sl": "Ta sloj prikazuje nadzorne kamere in urednikom omogoča posodabljanje informacij obstoječih in dodajanje novih kamer" | ||||||
|   }, |   }, | ||||||
|  |   "enableMorePrivacy": true, | ||||||
|   "source": { |   "source": { | ||||||
|     "osmTags": { |     "osmTags": { | ||||||
|       "and": [ |       "and": [ | ||||||
|  |  | ||||||
|  | @ -12,6 +12,7 @@ | ||||||
|   }, |   }, | ||||||
|   "icon": "./assets/layers/stripclub/stripclub.svg", |   "icon": "./assets/layers/stripclub/stripclub.svg", | ||||||
|   "hideFromOverview": true, |   "hideFromOverview": true, | ||||||
|  |   "enableMorePrivacy": true, | ||||||
|   "layers": [ |   "layers": [ | ||||||
|     "brothel", |     "brothel", | ||||||
|     "stripclub", |     "stripclub", | ||||||
|  |  | ||||||
|  | @ -52,6 +52,7 @@ | ||||||
|   }, |   }, | ||||||
|   "icon": "./assets/themes/surveillance/logo.svg", |   "icon": "./assets/themes/surveillance/logo.svg", | ||||||
|   "defaultBackgroundId": "maptiler.carto", |   "defaultBackgroundId": "maptiler.carto", | ||||||
|  |   "enableMorePrivacy": true, | ||||||
|   "layers": [ |   "layers": [ | ||||||
|     "surveillance_camera", |     "surveillance_camera", | ||||||
|     { |     { | ||||||
|  |  | ||||||
|  | @ -19,6 +19,7 @@ import Title from "../../UI/Base/Title" | ||||||
| import Table from "../../UI/Base/Table" | import Table from "../../UI/Base/Table" | ||||||
| import ChangeLocationAction from "./Actions/ChangeLocationAction" | import ChangeLocationAction from "./Actions/ChangeLocationAction" | ||||||
| import ChangeTagAction from "./Actions/ChangeTagAction" | import ChangeTagAction from "./Actions/ChangeTagAction" | ||||||
|  | import FeatureSwitchState from "../State/FeatureSwitchState" | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Handles all changes made to OSM. |  * Handles all changes made to OSM. | ||||||
|  | @ -28,7 +29,7 @@ export class Changes { | ||||||
|     public readonly pendingChanges: UIEventSource<ChangeDescription[]> = |     public readonly pendingChanges: UIEventSource<ChangeDescription[]> = | ||||||
|         LocalStorageSource.GetParsed<ChangeDescription[]>("pending-changes", []) |         LocalStorageSource.GetParsed<ChangeDescription[]>("pending-changes", []) | ||||||
|     public readonly allChanges = new UIEventSource<ChangeDescription[]>(undefined) |     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 extraComment: UIEventSource<string> = new UIEventSource(undefined) | ||||||
|     public readonly backend: string |     public readonly backend: string | ||||||
|     public readonly isUploading = new UIEventSource(false) |     public readonly isUploading = new UIEventSource(false) | ||||||
|  | @ -45,7 +46,8 @@ export class Changes { | ||||||
|             allElements?: IndexedFeatureSource |             allElements?: IndexedFeatureSource | ||||||
|             featurePropertiesStore?: FeaturePropertiesStore |             featurePropertiesStore?: FeaturePropertiesStore | ||||||
|             osmConnection: OsmConnection |             osmConnection: OsmConnection | ||||||
|             historicalUserLocations?: FeatureSource |             historicalUserLocations?: FeatureSource, | ||||||
|  |             featureSwitches?: FeatureSwitchState | ||||||
|         }, |         }, | ||||||
|         leftRightSensitive: boolean = false |         leftRightSensitive: boolean = false | ||||||
|     ) { |     ) { | ||||||
|  | @ -431,6 +433,9 @@ export class Changes { | ||||||
|             // Probably irrelevant, such as a new helper node
 |             // Probably irrelevant, such as a new helper node
 | ||||||
|             return |             return | ||||||
|         } |         } | ||||||
|  |         if(this.state.featureSwitches.featureSwitchMorePrivacy?.data){ | ||||||
|  |             return | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         const now = new Date() |         const now = new Date() | ||||||
|         const recentLocationPoints = locations |         const recentLocationPoints = locations | ||||||
|  |  | ||||||
|  | @ -6,14 +6,6 @@ import Constants from "../../Models/Constants" | ||||||
| import { Changes } from "./Changes" | import { Changes } from "./Changes" | ||||||
| import { Utils } from "../../Utils" | import { Utils } from "../../Utils" | ||||||
| import FeaturePropertiesStore from "../FeatureSource/Actors/FeaturePropertiesStore" | 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 { | export interface ChangesetTag { | ||||||
|     key: string |     key: string | ||||||
|  | @ -232,7 +224,7 @@ export class ChangesetHandler { | ||||||
|             if (newMetaTag === undefined) { |             if (newMetaTag === undefined) { | ||||||
|                 extraMetaTags.push({ |                 extraMetaTags.push({ | ||||||
|                     key: key, |                     key: key, | ||||||
|                     value: oldCsTags[key], |                     value: oldCsTags[key] | ||||||
|                 }) |                 }) | ||||||
|                 continue |                 continue | ||||||
|             } |             } | ||||||
|  | @ -361,21 +353,22 @@ export class ChangesetHandler { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private defaultChangesetTags(): ChangesetTag[] { |     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 [ |         return [ | ||||||
|             ["created_by", `MapComplete ${Constants.vNumber}`], |             ["created_by", `MapComplete ${Constants.vNumber}`], | ||||||
|             ["locale", Locale.language.data], |             ["locale", Locale.language.data], | ||||||
|             ["host", `${window.location.origin}${window.location.pathname}`], |             ["host", `${window.location.origin}${window.location.pathname}`], | ||||||
|             [ |             [ | ||||||
|                 "source", |                 "source", | ||||||
|                 this.changes.state["currentUserLocation"]?.features?.data?.length > 0 |                 setSourceAsSurvey                    ? "survey"                    : undefined | ||||||
|                     ? "survey" |  | ||||||
|                     : undefined, |  | ||||||
|             ], |             ], | ||||||
|             ["imagery", this.changes.state["backgroundLayer"]?.data?.id], |             ["imagery", this.changes.state["backgroundLayer"]?.data?.id] | ||||||
|         ].map(([key, value]) => ({ |         ].map(([key, value]) => ({ | ||||||
|             key, |             key, | ||||||
|             value, |             value, | ||||||
|             aggregate: false, |             aggregate: false | ||||||
|         })) |         })) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -63,6 +63,7 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches { | ||||||
|     public readonly overpassMaxZoom: UIEventSource<number> |     public readonly overpassMaxZoom: UIEventSource<number> | ||||||
|     public readonly osmApiTileSize: UIEventSource<number> |     public readonly osmApiTileSize: UIEventSource<number> | ||||||
|     public readonly backgroundLayerId: UIEventSource<string> |     public readonly backgroundLayerId: UIEventSource<string> | ||||||
|  |     public readonly featureSwitchMorePrivacy: UIEventSource<boolean> | ||||||
| 
 | 
 | ||||||
|     public constructor(layoutToUse?: LayoutConfig) { |     public constructor(layoutToUse?: LayoutConfig) { | ||||||
|         super() |         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" |             "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( |         this.overpassUrl = QueryParameters.GetQueryParameter( | ||||||
|             "overpassUrl", |             "overpassUrl", | ||||||
|             (layoutToUse?.overpassUrl ?? Constants.defaultOverpassUrls).join(","), |             (layoutToUse?.overpassUrl ?? Constants.defaultOverpassUrls).join(","), | ||||||
|  |  | ||||||
|  | @ -554,4 +554,15 @@ export interface LayerConfigJson { | ||||||
|      * group: hidden |      * group: hidden | ||||||
|      */ |      */ | ||||||
|     fullNodeDatabase?: boolean |     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 |      * group: hidden | ||||||
|      */ |      */ | ||||||
|     enableNodeDatabase?: boolean |     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 _needsFullNodeDatabase: boolean | ||||||
|     public readonly popupInFloatover: boolean | string |     public readonly popupInFloatover: boolean | string | ||||||
|  |     public readonly enableMorePrivacy: boolean | ||||||
| 
 | 
 | ||||||
|     constructor(json: LayerConfigJson, context?: string, official: boolean = true) { |     constructor(json: LayerConfigJson, context?: string, official: boolean = true) { | ||||||
|         context = context + "." + json.id |         context = context + "." + json.id | ||||||
|  | @ -149,6 +150,7 @@ export default class LayerConfig extends WithContextLoader { | ||||||
|         this.shownByDefault = json.shownByDefault ?? true |         this.shownByDefault = json.shownByDefault ?? true | ||||||
|         this.doCount = json.isCounted ?? this.shownByDefault ?? true |         this.doCount = json.isCounted ?? this.shownByDefault ?? true | ||||||
|         this.forceLoad = json.forceLoad ?? false |         this.forceLoad = json.forceLoad ?? false | ||||||
|  |         this.enableMorePrivacy = json.enableMorePrivacy ?? false | ||||||
|         if (json.presets === null) json.presets = undefined |         if (json.presets === null) json.presets = undefined | ||||||
|         if (json.presets !== undefined && json.presets?.map === undefined) { |         if (json.presets !== undefined && json.presets?.map === undefined) { | ||||||
|             throw "Presets should be a list of items (at " + context + ")" |             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 enableExportButton: boolean | ||||||
|     public readonly enablePdfDownload: boolean |     public readonly enablePdfDownload: boolean | ||||||
|     public readonly enableTerrain: boolean |     public readonly enableTerrain: boolean | ||||||
|  |     public readonly enableMorePrivacy: boolean | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     public readonly customCss?: string |     public readonly customCss?: string | ||||||
| 
 | 
 | ||||||
|  | @ -204,6 +206,7 @@ export default class LayoutConfig implements LayoutInformation { | ||||||
|         this.overpassTimeout = json.overpassTimeout ?? 30 |         this.overpassTimeout = json.overpassTimeout ?? 30 | ||||||
|         this.overpassMaxZoom = json.overpassMaxZoom ?? 16 |         this.overpassMaxZoom = json.overpassMaxZoom ?? 16 | ||||||
|         this.osmApiTileSize = json.osmApiTileSize ?? this.overpassMaxZoom + 1 |         this.osmApiTileSize = json.osmApiTileSize ?? this.overpassMaxZoom + 1 | ||||||
|  |         this.enableMorePrivacy = json.enableMorePrivacy || json.layers.some(l => (<LayerConfigJson> l).enableMorePrivacy) | ||||||
| 
 | 
 | ||||||
|         this.layersDict = new Map<string, LayerConfig>() |         this.layersDict = new Map<string, LayerConfig>() | ||||||
|         for (const layer of this.layers) { |         for (const layer of this.layers) { | ||||||
|  |  | ||||||
|  | @ -265,6 +265,7 @@ export default class ThemeViewState implements SpecialVisualizationState { | ||||||
|                     featurePropertiesStore: this.featureProperties, |                     featurePropertiesStore: this.featureProperties, | ||||||
|                     osmConnection: this.osmConnection, |                     osmConnection: this.osmConnection, | ||||||
|                     historicalUserLocations: this.geolocation.historicalUserLocations, |                     historicalUserLocations: this.geolocation.historicalUserLocations, | ||||||
|  |                     featureSwitches: this.featureSwitches | ||||||
|                 }, |                 }, | ||||||
|                 layout?.isLeftRightSensitive() ?? false |                 layout?.isLeftRightSensitive() ?? false | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue