import * as packagefile from "../../package.json" import * as extraconfig from "../../config.json" import { AuthConfig } from "../Logic/Osm/AuthConfig" import { ServerSourceInfo } from "./SourceOverview" export type PriviligedLayerType = (typeof Constants.priviliged_layers)[number] export type DefaultPinIcon = (typeof Constants._defaultPinIcons)[number] export default class Constants { public static vNumber: string = packagefile.version /** * API key for Maproulette * * There is no user-friendly way to get the user's API key currently. * See https://github.com/maproulette/maproulette2/issues/476 for more information. * Using an empty string however does work for most actions, but will attribute all actions to the Superuser. */ public static readonly MaprouletteApiKey = "" public static readonly added_by_default = [ "selected_element", "gps_location", "gps_location_history", "home_location", "gps_track", "range", "last_click", "favourite", "summary", "search", "geocoded_image", ] as const /** * Special layers which are not included in a theme by default */ public static readonly no_include = [ "conflation", "split_point", "split_road", "current_view", "import_candidate", "usersettings", "icons", "filters", ] as const /** * Layer IDs of layers which have special properties through built-in hooks */ public static readonly priviliged_layers = [ ...Constants.added_by_default, ...Constants.no_include, ] as const public static panoramax: { url: string token: string sequence: string testsequence: string } & ServerSourceInfo = { ...packagefile.config.panoramax, description: "The panoramax-server that MapComplete uploads to", category: "core", sourceAvailable: true, openData: true, selfhostable: true, moreInfo: ["https://wiki.openstreetmap.org/wiki/Panoramax"] } // The user journey states thresholds when a new feature gets unlocked public static userJourney = { moreScreenUnlock: 1, personalThemeUnlock: 5, historyLinkVisible: 10, deletePointsOfOthersUnlock: 20, tagsVisibleAt: 25, tagsVisibleAndWikiLinked: 30, mapCompleteHelpUnlock: 50, themeGeneratorReadOnlyUnlock: 50, addNewPointWithUnreadMessagesUnlock: 500, importHelperUnlock: 5000, } static readonly minZoomLevelToAddNewPoint = 18 /** * Used by 'PendingChangesUploader', which waits this amount of seconds to upload changes. * (Note that pendingChanges might upload sooner if the popup is closed or similar) */ static updateTimeoutSec: number = 15 /** * If the contributor has their GPS location enabled and makes a change, * the points visited less then `nearbyVisitTime`-seconds ago will be inspected. * The point closest to the changed feature will be considered and this distance will be tracked. * ALl these distances are used to calculate a nearby-score */ static nearbyVisitTime: number = 30 * 60 /** * If a user makes a change, the distance to the changed object is calculated. * If a user makes multiple changes, all these distances are put into multiple bins, depending on this distance. * For every bin, the totals are uploaded as metadata */ static distanceToChangeObjectBins = [25, 50, 100, 500, 1000, 5000, Number.MAX_VALUE] static themeOrder = [ "personal", "cyclofix", "etymology", "waste", "food", "cafes_and_pubs", "shops", "healthcare", "sports", "artwork", "bookcases", "playgrounds", "drinking_water", "toilets", "vending_machine", "aed", "clock", "charging_stations", "surveillance", "advertising", "circular_economy", ] /** * Upon initialization, the GPS will search the location. * If the location is found within the given timout, it'll automatically fly to it. * * In seconds */ static zoomToLocationTimeout = 15 public static readonly viewportCenterCloseToGpsCutoff: number = 20 private static readonly config = (() => { const defaultConfig = packagefile.config return { ...defaultConfig, ...extraconfig } })() public static ImgurApiKey = Constants.config.api_keys.imgur public static readonly mapillary_client_token_v4 = Constants.config.api_keys.mapillary_v4 public static defaultOverpassUrls = Constants.config.default_overpass_urls public static countryCoderEndpoint: string = Constants.config.country_coder_host public static countryCoderInfo: ServerSourceInfo = { url: this.countryCoderEndpoint, trigger: ["always"], openData: true, category: "core", logging: "no", selfhostable: true, sourceAvailable: true, moreInfo:["https://source.mapcomplete.org/MapComplete/latlon2country"], description: "For quite some functions, we need to know in what _country_ a feature is located. LatLon2Country is a static dataset, which, by cleverly encoding the data, can quickly tell in what country a feature is located." } public static communityIndexHost: string = Constants.config.community_index_host private static osmServerInfo: Omit = { trigger: ["always"], description: "Login service, by OpenStreetMap.org", sourceAvailable: true, openData: true, selfhostable: "partially - a copy can be hosted, but this would be useless", category: "core", moreInfo: ["https://www.openstreetmap.org/copyright","https://www.openstreetmap.org/about", "https://osmfoundation.org/wiki/Privacy_Policy"] } public static osmAuthConfig: AuthConfig & ServerSourceInfo= {... Constants.config.oauth_credentials, ...this.osmServerInfo } public static nominatimEndpoint: string = Constants.config.nominatimEndpoint public static nominatimEndpointInfo: ServerSourceInfo = { url: this.nominatimEndpoint, description: "Nominatim search engine endpoint, used when searching", selfhostable: true, openData: true, sourceAvailable: true, category: "core", trigger:["specific_feature"], moreInfo: ["https://wiki.openstreetmap.org/wiki/Nominatim"] } public static photonEndpoint: string = Constants.config.photonEndpoint public static photonEndpointInfo: ServerSourceInfo = { url: this.photonEndpoint, description: "Endpoint for search with photon", sourceAvailable: true, selfhostable: true, openData: true, category: "core", trigger: ["specific_feature"], moreInfo: ["https://wiki.openstreetmap.org/wiki/Photon"] } public static nsiLogosEndpoint: string = Constants.config.nsi_logos_server ?? null public static weblate: string = "https://translate.mapcomplete.org/" public static linkedDataProxy: string = Constants.config["jsonld-proxy"] public static linkedDataProxyInfo: ServerSourceInfo = { url: Constants.config["jsonld-proxy"], trigger: ["specific_feature"], category: "core", openData: true, description: "This proxy queries websites to detect if they contain linked open data and gives this data back. Triggered by opening a feature", sourceAvailable: true, selfhostable: true, moreInfo: ["https://source.mapcomplete.org/MapComplete/MapComplete/src/branch/develop/scripts/serverLdScrape.ts"] } /** * These are the values that are allowed to use as 'backdrop' icon for a map pin */ public static readonly _defaultPinIcons = [ "addSmall", "airport", "brick_wall_round", "brick_wall_square", "building_office_2", "building_storefront", "bug", "checkmark", "checkmark", "circle", "clock", "close", "close", "confirm", "computer", "cross_bottom_right", "crosshair", "desktop", "direction", "gear", "globe_alt", "gps_arrow", "heart", "heart_outline", "help", "help", "home", "house", "key", "invalid", "invalid", "link", "location", "location_empty", "location_locked", "lock", "mastodon", "not_found", "note", "party", "pencil", "pin", "resolved", "ring", "scissors", "snowflake", "square", "square_rounded", "teardrop", "teardrop_with_hole_green", "train", "triangle", "user_circle", "wifi", ] as const public static readonly defaultPinIcons: string[] = Constants._defaultPinIcons /** * The location that the MVT-layer is hosted. * This is a MapLibre/MapBox vector tile server which hosts vector tiles for every (official) layer */ public static VectorTileServer: string | undefined = Constants.config.mvt_layer_server public static vectorTileServerInfo: ServerSourceInfo = { url: this.VectorTileServer, description: "The vectortileserver is a cache of OSM data and can be used as an alternative for overpass to actually show data, esp on low zoom levels", selfhostable: true, openData: true, category: "core", sourceAvailable: true, trigger: ["always"], moreInfo: ["https://source.mapcomplete.org/MapComplete/MapComplete/src/branch/develop/Docs/SettingUpPSQL.md"] } public static GeoIpServer: string | undefined = Constants.config.geoip_server public static geoIpServerInfo: ServerSourceInfo = { url: this.GeoIpServer, category: "core", description: "When opening MapComplete for the first time, we try to set the map at a relevant location. For this, we try to determine the location based on the IP-address; this is done by this service.", selfhostable: true, openData: false, trigger: ["always"], sourceAvailable: true } public static ErrorReportServer: string | undefined = Constants.config.error_server public static errorReportServerInfo: ServerSourceInfo = { url: this.ErrorReportServer, logging: "yes", category: "core", selfhostable: "yes", openData: "no (privacy)", trigger: ["on_failure"], description: "If a severe error occurs in MapComplete, this is logged on this server - this mostly concerns errors where making a change to OpenStreetMap failed. Data is handled confidentially and _only_ to replay the change and fix the root cause." } public static readonly SummaryServer: string = Constants.config.summary_server public static readonly summaryServerInfo: ServerSourceInfo = { url: this.SummaryServer, trigger: ["always"], category: "core", selfhostable: true, sourceAvailable: true, openData: true, description: "This server indicates how much items there are (according to OpenStreetMap) at a given slippy tile coordinate" } public static allServers: ServerSourceInfo[] = [ Constants.summaryServerInfo, Constants.vectorTileServerInfo, Constants.geoIpServerInfo, Constants.errorReportServerInfo, Constants.osmAuthConfig, Constants.countryCoderInfo, Constants.nominatimEndpointInfo, Constants.photonEndpointInfo, ...Constants.defaultOverpassUrls.map(url => ({ url, openData: true, selfhostable: true, trigger: ["always"], sourceAvailable: true, category: "core", description: "Overpass is a query service where OpenStreetMap-data can be retrieved. Various overpass-servers are used to query this data", moreInfo: ["https://wiki.openstreetmap.org/wiki/Overpass_turbo"] })), ] private static priviligedLayerSet = new Set(Constants.priviliged_layers) public static isPriviliged(layer: string | { id: string }) { let id: string if (typeof layer === "string") { id = layer } else { id = layer.id } return this.priviligedLayerSet.has(id) } }