Merge branch 'bug/disable-address-autocomplete-when-requried' into 'master'

Disable address autocomplete where required (nominatim)

See merge request framasoft/mobilizon!327
This commit is contained in:
Thomas Citharel 2019-11-20 14:10:04 +01:00
commit 359bbe5449
17 changed files with 220 additions and 80 deletions

View File

@ -143,6 +143,14 @@ config :mobilizon, Mobilizon.Service.Geospatial.Mimirsbrunn,
config :mobilizon, Mobilizon.Service.Geospatial.Pelias, config :mobilizon, Mobilizon.Service.Geospatial.Pelias,
endpoint: System.get_env("GEOSPATIAL_PELIAS_ENDPOINT") || nil endpoint: System.get_env("GEOSPATIAL_PELIAS_ENDPOINT") || nil
config :mobilizon, :maps,
tiles: [
endpoint:
System.get_env("MAPS_TILES_ENDPOINT") ||
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
attribution: System.get_env("MAPS_TILES_ATTRIBUTION")
]
config :mobilizon, Oban, config :mobilizon, Oban,
repo: Mobilizon.Storage.Repo, repo: Mobilizon.Storage.Repo,
prune: {:maxlen, 10_000}, prune: {:maxlen, 10_000},

View File

@ -52,7 +52,7 @@ config :mobilizon, MobilizonWeb.Endpoint,
# Do not include metadata nor timestamps in development logs # Do not include metadata nor timestamps in development logs
config :logger, :console, format: "[$level] $message\n", level: :debug config :logger, :console, format: "[$level] $message\n", level: :debug
config :mobilizon, Mobilizon.Service.Geospatial, service: Mobilizon.Service.Geospatial.Nominatim config :mobilizon, Mobilizon.Service.Geospatial, service: Mobilizon.Service.Geospatial.Mimirsbrunn
# Set a higher stacktrace during development. Avoid configuring such # Set a higher stacktrace during development. Avoid configuring such
# in production as building large stacktraces may be expensive. # in production as building large stacktraces may be expensive.

View File

@ -7,8 +7,8 @@ This is needed to set correct address for events, and more easily find events wi
However, providing a geocoding service is quite expensive, especially if you want to cover the whole Earth. However, providing a geocoding service is quite expensive, especially if you want to cover the whole Earth.
!!!note !!! note "Hardware setup"
To give an idea of what hardware is required to self-host a geocoding service, we successfully used Addok, Pelias and Mimirsbrunn on a 8 core/16GB RAM machine without any issues **on French data**. To give an idea of what hardware is required to self-host a geocoding service, we successfully installed and used [Addok](#addok), [Pelias](#pelias) and [Mimirsbrunn](#mimirsbrunn) on a 8 cores/16GB RAM machine without any issues **importing only French addresses and data**.
## List of supported geocoders ## List of supported geocoders
@ -27,9 +27,12 @@ This is the list of all geocoders supported by Mobilizon. The current default on
[Nominatim](https://wiki.openstreetmap.org/wiki/Nominatim) is a GPL-2.0 licenced tool to search data by name and address. It's written in C and PHP and uses PostgreSQL. [Nominatim](https://wiki.openstreetmap.org/wiki/Nominatim) is a GPL-2.0 licenced tool to search data by name and address. It's written in C and PHP and uses PostgreSQL.
It's the current default search tool on the [OpenStreetMap homepage](https://www.openstreetmap.org). It's the current default search tool on the [OpenStreetMap homepage](https://www.openstreetmap.org).
!!! warning !!! warning "Terms"
When using the official Nominatim OpenStreetMap instance (default endpoint for this geocoder if not configured otherwise), you need to read and accept the [Usage Policy](https://operations.osmfoundation.org/policies/nominatim). When using the official Nominatim OpenStreetMap instance (default endpoint for this geocoder if not configured otherwise), you need to read and accept the [Usage Policy](https://operations.osmfoundation.org/policies/nominatim).
!!! danger "Limitations"
Autocomplete is not possible using Nominatim, you'll obtain no suggestions while typing.
Several companies provide hosted instances of Nominatim that you can query via an API, for example see [MapQuest Open Initiative](https://developer.mapquest.com/documentation/open/nominatim-search). Several companies provide hosted instances of Nominatim that you can query via an API, for example see [MapQuest Open Initiative](https://developer.mapquest.com/documentation/open/nominatim-search).
### Addok ### Addok
@ -37,14 +40,14 @@ Several companies provide hosted instances of Nominatim that you can query via a
[Addok](https://github.com/addok/addok) is a WTFPL licenced search engine for address (and only address). It's written in Python and uses Redis. [Addok](https://github.com/addok/addok) is a WTFPL licenced search engine for address (and only address). It's written in Python and uses Redis.
It's used by French government for [adresse.data.gouv.fr](https://adresse.data.gouv.fr). It's used by French government for [adresse.data.gouv.fr](https://adresse.data.gouv.fr).
!!! warning !!! warning "Terms"
When using France's Addok instance at `api-adresse.data.gouv.fr` (default endpoint for this geocoder if not configured otherwise), you need to read and accept the [GCU](https://adresse.data.gouv.fr/cgu) (in French). When using France's Addok instance at `api-adresse.data.gouv.fr` (default endpoint for this geocoder if not configured otherwise), you need to read and accept the [GCU](https://adresse.data.gouv.fr/cgu) (in French).
### Photon ### Photon
[Photon](https://photon.komoot.de/) is an Apache 2.0 licenced search engine written in Java and powered by ElasticSearch. [Photon](https://photon.komoot.de/) is an Apache 2.0 licenced search engine written in Java and powered by ElasticSearch.
!!! warning !!! warning "Terms"
The terms of use for the official instance (default endpoint for this geocoder if not configured otherwise) are simply the following: The terms of use for the official instance (default endpoint for this geocoder if not configured otherwise) are simply the following:
> You can use the API for your project, but please be fair - extensive usage will be throttled. We do not guarantee for the availability and usage might be subject of change in the future. > You can use the API for your project, but please be fair - extensive usage will be throttled. We do not guarantee for the availability and usage might be subject of change in the future.

View File

@ -7,12 +7,12 @@
<span v-else>{{ $t('Getting location') }}</span> <span v-else>{{ $t('Getting location') }}</span>
</template> </template>
<b-autocomplete <b-autocomplete
:data="data" :data="addressData"
v-model="queryText" v-model="queryText"
:placeholder="$t('e.g. 10 Rue Jangot')" :placeholder="$t('e.g. 10 Rue Jangot')"
field="fullName" field="fullName"
:loading="isFetching" :loading="isFetching"
@typing="getAsyncData" @typing="fetchAsyncData"
icon="map-marker" icon="map-marker"
expanded expanded
@select="updateSelected"> @select="updateSelected">
@ -24,7 +24,7 @@
</template> </template>
<template slot="empty"> <template slot="empty">
<span v-if="isFetching">{{ $t('Searching') }}</span> <span v-if="isFetching">{{ $t('Searching') }}</span>
<div v-else class="is-enabled"> <div v-else-if="queryText.length >= 3" class="is-enabled">
<span>{{ $t('No results for "{queryText}"') }}</span> <span>{{ $t('No results for "{queryText}"') }}</span>
<span>{{ $t('You can try another search term or drag and drop the marker on the map', { queryText }) }}</span> <span>{{ $t('You can try another search term or drag and drop the marker on the map', { queryText }) }}</span>
<!-- <p class="control" @click="openNewAddressModal">--> <!-- <p class="control" @click="openNewAddressModal">-->
@ -92,19 +92,25 @@ import { Address, IAddress } from '@/types/address.model';
import { ADDRESS, REVERSE_GEOCODE } from '@/graphql/address'; import { ADDRESS, REVERSE_GEOCODE } from '@/graphql/address';
import { Modal } from 'buefy/dist/components/dialog'; import { Modal } from 'buefy/dist/components/dialog';
import { LatLng } from 'leaflet'; import { LatLng } from 'leaflet';
import { debounce } from 'lodash';
import { CONFIG } from '@/graphql/config';
import { IConfig } from '@/types/config.model';
@Component({ @Component({
components: { components: {
'map-leaflet': () => import(/* webpackChunkName: "map" */ '@/components/Map.vue'), 'map-leaflet': () => import(/* webpackChunkName: "map" */ '@/components/Map.vue'),
Modal, Modal,
}, },
apollo: {
config: CONFIG,
},
}) })
export default class AddressAutoComplete extends Vue { export default class AddressAutoComplete extends Vue {
@Prop({ required: true }) value!: IAddress; @Prop({ required: true }) value!: IAddress;
data: IAddress[] = []; addressData: IAddress[] = [];
selected!: IAddress; selected: IAddress = new Address();
isFetching: boolean = false; isFetching: boolean = false;
queryText: string = this.value && (new Address(this.value)).fullName || ''; queryText: string = this.value && (new Address(this.value)).fullName || '';
addressModalActive: boolean = false; addressModalActive: boolean = false;
@ -112,25 +118,27 @@ export default class AddressAutoComplete extends Vue {
private location!: Position; private location!: Position;
private gettingLocationError: any; private gettingLocationError: any;
private mapDefaultZoom: number = 15; private mapDefaultZoom: number = 15;
config!: IConfig;
@Watch('value') // We put this in data because of issues like https://github.com/vuejs/vue-class-component/issues/263
updateEditing() { data() {
this.selected = this.value; return {
const address = new Address(this.selected); fetchAsyncData: debounce(this.asyncData, 500),
this.queryText = `${address.poiInfos.name} ${address.poiInfos.alternativeName}`; };
} }
async getAsyncData(query) { async asyncData(query: String) {
if (!query.length) { if (!query.length) {
this.data = []; this.addressData = [];
this.selected = new Address(); this.selected = new Address();
return; return;
} }
if (query.length < 3) { if (query.length < 3) {
this.data = []; this.addressData = [];
return; return;
} }
this.isFetching = true; this.isFetching = true;
const result = await this.$apollo.query({ const result = await this.$apollo.query({
query: ADDRESS, query: ADDRESS,
@ -141,14 +149,29 @@ export default class AddressAutoComplete extends Vue {
}, },
}); });
this.data = result.data.searchAddress.map(address => new Address(address)); this.addressData = result.data.searchAddress.map(address => new Address(address));
this.isFetching = false; this.isFetching = false;
} }
@Watch('config')
watchConfig(config: IConfig) {
if (!config.geocoding.autocomplete) {
// If autocomplete is disabled, we put a larger debounce value so that we don't request with incomplete address
// @ts-ignore
this.fetchAsyncData = debounce(this.asyncData, 2000);
}
}
@Watch('value')
updateEditing() {
this.selected = this.value;
const address = new Address(this.selected);
this.queryText = `${address.poiInfos.name} ${address.poiInfos.alternativeName}`;
}
updateSelected(option) { updateSelected(option) {
if (option == null) return; if (option == null) return;
this.selected = option; this.selected = option;
console.log('update selected', this.selected);
this.$emit('input', this.selected); this.$emit('input', this.selected);
} }
@ -174,8 +197,8 @@ export default class AddressAutoComplete extends Vue {
}, },
}); });
this.data = result.data.reverseGeocode.map(address => new Address(address)); this.addressData = result.data.reverseGeocode.map(address => new Address(address));
const defaultAddress = new Address(this.data[0]); const defaultAddress = new Address(this.addressData[0]);
this.selected = defaultAddress; this.selected = defaultAddress;
this.$emit('input', this.selected); this.$emit('input', this.selected);
this.queryText = `${defaultAddress.poiInfos.name} ${defaultAddress.poiInfos.alternativeName}`; this.queryText = `${defaultAddress.poiInfos.name} ${defaultAddress.poiInfos.alternativeName}`;

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="map-container"> <div class="map-container" v-if="config">
<l-map <l-map
:zoom="mergedOptions.zoom" :zoom="mergedOptions.zoom"
:style="`height: ${mergedOptions.height}; width: ${mergedOptions.width}`" :style="`height: ${mergedOptions.height}; width: ${mergedOptions.width}`"
@ -9,8 +9,8 @@
@update:zoom="updateZoom" @update:zoom="updateZoom"
> >
<l-tile-layer <l-tile-layer
url="https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png" :url="config.maps.tiles.endpoint"
:attribution="$t('© The OpenStreetMap Contributors')" :attribution="attribution"
> >
</l-tile-layer> </l-tile-layer>
@ -30,9 +30,14 @@ import 'leaflet/dist/leaflet.css';
import { Component, Prop, Vue } from 'vue-property-decorator'; import { Component, Prop, Vue } from 'vue-property-decorator';
import { LMap, LTileLayer, LMarker, LPopup, LIcon } from 'vue2-leaflet'; import { LMap, LTileLayer, LMarker, LPopup, LIcon } from 'vue2-leaflet';
import Vue2LeafletLocateControl from '@/components/Map/Vue2LeafletLocateControl.vue'; import Vue2LeafletLocateControl from '@/components/Map/Vue2LeafletLocateControl.vue';
import { CONFIG } from '@/graphql/config';
import { IConfig } from '@/types/config.model';
@Component({ @Component({
components: { LTileLayer, LMap, LMarker, LPopup, LIcon, 'v-locatecontrol': Vue2LeafletLocateControl }, components: { LTileLayer, LMap, LMarker, LPopup, LIcon, 'v-locatecontrol': Vue2LeafletLocateControl },
apollo: {
config: CONFIG,
},
}) })
export default class Map extends Vue { export default class Map extends Vue {
@Prop({ type: Boolean, required: false, default: true }) readOnly!: boolean; @Prop({ type: Boolean, required: false, default: true }) readOnly!: boolean;
@ -52,6 +57,7 @@ export default class Map extends Vue {
}; };
zoom = this.defaultOptions.zoom; zoom = this.defaultOptions.zoom;
config!: IConfig;
mounted() { mounted() {
// this part resolve an issue where the markers would not appear // this part resolve an issue where the markers would not appear
@ -90,13 +96,16 @@ export default class Map extends Vue {
} }
updateDraggableMarkerPosition(e: LatLng) { updateDraggableMarkerPosition(e: LatLng) {
console.log('updateDraggableMarkerPosition', e);
this.updateDraggableMarkerCallback(e, this.zoom); this.updateDraggableMarkerCallback(e, this.zoom);
} }
updateZoom(zoom: Number) { updateZoom(zoom: Number) {
this.zoom = zoom; this.zoom = zoom;
} }
get attribution() {
return this.config.maps.tiles.attribution || this.$t('© The OpenStreetMap Contributors');
}
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -11,6 +11,16 @@ query {
latitude, latitude,
longitude, longitude,
accuracyRadius accuracyRadius
},
maps {
tiles {
endpoint,
attribution
}
},
geocoding {
provider,
autocomplete
} }
} }
} }

View File

@ -9,4 +9,14 @@ export interface IConfig {
longitude: number; longitude: number;
accuracyRadius: number; accuracyRadius: number;
}; };
maps: {
tiles: {
endpoint: string;
attribution: string|null;
},
};
geocoding: {
provider: string;
autocomplete: boolean;
};
} }

View File

@ -982,9 +982,9 @@
integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==
"@types/node@*", "@types/node@>=6": "@types/node@*", "@types/node@>=6":
version "12.12.9" version "12.12.11"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.9.tgz#0b5ae05516b757cbff2e82c04500190aef986c7b" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.11.tgz#bec2961975888d964196bf0016a2f984d793d3ce"
integrity sha512-kV3w4KeLsRBW+O2rKhktBwENNJuqAUQHS3kf4ia2wIaF/MN6U7ANgTsx7tGremcA0Pk3Yh0Hl0iKiLPuBdIgmw== integrity sha512-O+x6uIpa6oMNTkPuHDa9MhMMehlxLAd5QcOvKRjAFsBVpeFWTOPnXbDvILvFgFFZfQ1xh1EZi1FbXxUix+zpsQ==
"@types/normalize-package-data@^2.4.0": "@types/normalize-package-data@^2.4.0":
version "2.4.0" version "2.4.0"
@ -2522,9 +2522,9 @@ buble@0.19.8, buble@^0.19.7:
regexpu-core "^4.5.4" regexpu-core "^4.5.4"
buefy@^0.8.2: buefy@^0.8.2:
version "0.8.6" version "0.8.7"
resolved "https://registry.yarnpkg.com/buefy/-/buefy-0.8.6.tgz#a8d7e570914b95d8d5aadc40f87bcdfbaf552f0e" resolved "https://registry.yarnpkg.com/buefy/-/buefy-0.8.7.tgz#ccfe47001156f3fab8bf3c5e5339ec646dca1b58"
integrity sha512-7woxrdwANcnJbe7lofPxkJLGRRGIVwFXOo0kzEpiNB6alQj18NV6UrdAKse+LWCOADz+AeHe5gyc6qdgRjG5mw== integrity sha512-Nmd6yuNPTQkwGXflLeRCINnLQWvDZcDqbw+7sy+LjX0n5kP5kcJ4DFc43koO+yPd4MpB7ZheHhLk5Sn00NnToA==
dependencies: dependencies:
bulma "0.7.5" bulma "0.7.5"
@ -2765,9 +2765,9 @@ caniuse-api@^3.0.0:
lodash.uniq "^4.5.0" lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000929, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30001010: caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000929, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30001010:
version "1.0.30001010" version "1.0.30001011"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001010.tgz#397a14034d384260453cc81994f494626d34b938" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001011.tgz#0d6c4549c78c4a800bb043a83ca0cbe0aee6c6e1"
integrity sha512-RA5GH9YjFNea4ZQszdWgh2SC+dpLiRAg4VDQS2b5JRI45OxmbGrYocYHTa9x0bKMQUE7uvHkNPNffUr+pCxSGw== integrity sha512-h+Eqyn/YA6o6ZTqpS86PyRmNWOs1r54EBDcd2NTwwfsXQ8re1B38SnB+p2RKF8OUsyEIjeDU8XGec1RGO/wYCg==
capture-stack-trace@^1.0.0: capture-stack-trace@^1.0.0:
version "1.0.1" version "1.0.1"
@ -4441,14 +4441,14 @@ ee-first@1.1.1:
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
ejs@^2.6.1: ejs@^2.6.1:
version "2.7.3" version "2.7.4"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.3.tgz#4f437b3992ea0e0757f0ab8d7f29e42593498927" resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba"
integrity sha512-NtMNsdpaCF23gvHItgT37gzrpzckzs7KB7mg+YH1GMSG/5iZRq1BeWzAhEAJVagfM7nCQDnh/C51j/L2qjZmnA== integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==
electron-to-chromium@^1.3.103, electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.306: electron-to-chromium@^1.3.103, electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.306:
version "1.3.306" version "1.3.307"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.306.tgz#e8265301d053d5f74e36cb876486830261fbe946" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.307.tgz#e9b98901371d20164af7c0ca5bc820bd4305ccd3"
integrity sha512-frDqXvrIROoYvikSKTIKbHbzO6M3/qC6kCIt/1FOa9kALe++c4VAJnwjSFvf1tYLEUsP2n9XZ4XSCyqc3l7A/A== integrity sha512-01rTsAqHwf3D2X6NtlUvzB2hxDj67kiTVIO5GWdFb2unA0QvFvrjyrtc993ByRLF+surlr+9AvJdD0UYs5HzwA==
elegant-spinner@^1.0.1: elegant-spinner@^1.0.1:
version "1.0.1" version "1.0.1"
@ -9960,34 +9960,34 @@ prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
react-is "^16.8.1" react-is "^16.8.1"
prosemirror-collab@^1.1.2: prosemirror-collab@^1.1.2:
version "1.2.1" version "1.2.2"
resolved "https://registry.yarnpkg.com/prosemirror-collab/-/prosemirror-collab-1.2.1.tgz#478b4cb235dc6fa4f65e3069570b5e58e887d733" resolved "https://registry.yarnpkg.com/prosemirror-collab/-/prosemirror-collab-1.2.2.tgz#8d2c0e82779cfef5d051154bd0836428bd6d9c4a"
integrity sha512-Ycj4NHkYmRILJp34DvnQBft1j4b3Q+R59cdnWTQXxPytT/XKS10u/r9DaoI5emxt1+r095/wW5pbxJAQVfU79Q== integrity sha512-tBnHKMLgy5Qmx9MYVcLfs3pAyjtcqYYDd9kp3y+LSiQzkhMQDfZSV3NXWe4Gsly32adSef173BvObwfoSQL5MA==
dependencies: dependencies:
prosemirror-state "^1.0.0" prosemirror-state "^1.0.0"
prosemirror-commands@^1.0.8: prosemirror-commands@^1.0.8:
version "1.1.1" version "1.1.2"
resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.1.1.tgz#58cfe7480bb040a7dc6d5666e2e6f2bed61d556a" resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.1.2.tgz#6868cabc9f9112fba94c805139473527774b0dea"
integrity sha512-YWgSHU8CzJCYQ7tzQzHwBNz8x1QvXxnZ+du5ctQRpCGlkupg+gg9pZk3s/7nBh9GtoNAneGJYPGGj+flx/RKEA== integrity sha512-JBa06kjgX67d9JVUVJbCkxwvSGtQnWAN/85nq9csOMS5Z9WZLEvVDtVvZranNlu8l/XNVBWrZxOOK+pB03eTfA==
dependencies: dependencies:
prosemirror-model "^1.0.0" prosemirror-model "^1.0.0"
prosemirror-state "^1.0.0" prosemirror-state "^1.0.0"
prosemirror-transform "^1.0.0" prosemirror-transform "^1.0.0"
prosemirror-dropcursor@^1.2.0: prosemirror-dropcursor@^1.2.0:
version "1.3.1" version "1.3.2"
resolved "https://registry.yarnpkg.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.3.1.tgz#b649b72f399782007ed0f55b788f3cdb2085ce06" resolved "https://registry.yarnpkg.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.3.2.tgz#28738c4ed7102e814d7a8a26d70018523fc7cd6d"
integrity sha512-UkbHmYA56LruNNTONFPUnEPwfXnYf5wp+xo4MBF4bsH8iHE2D9RKy5AvqqyfKq8MtK0ThaRkvuRVjwvm0l2QNQ== integrity sha512-4c94OUGyobGnwcQI70OXyMhE/9T4aTgjU+CHxkd5c7D+jH/J0mKM/lk+jneFVKt7+E4/M0D9HzRPifu8U28Thw==
dependencies: dependencies:
prosemirror-state "^1.0.0" prosemirror-state "^1.0.0"
prosemirror-transform "^1.1.0" prosemirror-transform "^1.1.0"
prosemirror-view "^1.1.0" prosemirror-view "^1.1.0"
prosemirror-gapcursor@^1.0.4: prosemirror-gapcursor@^1.0.4:
version "1.1.1" version "1.1.2"
resolved "https://registry.yarnpkg.com/prosemirror-gapcursor/-/prosemirror-gapcursor-1.1.1.tgz#e24133f7bd63e4a985e87ec779cc9594d98bfa21" resolved "https://registry.yarnpkg.com/prosemirror-gapcursor/-/prosemirror-gapcursor-1.1.2.tgz#a1400a86a51d4cccc065e68d5625a9fb5bc623e0"
integrity sha512-bZ2LoTk4h/wjr14f0DB/BcUfk3UA8aI4MBi6OeCOIzHAhieu2CbBpG1t4mxNKC6Cd78PccwUXgix7VXC5BLzrQ== integrity sha512-Z+eqk6RysZVxidGWN5aWoSTbn5bTHf1XZ+nQJVwUSdwdBVkfQMFdTHgfrXA8W5MhHHdNg/EEEYG3z3Zi/vE2QQ==
dependencies: dependencies:
prosemirror-keymap "^1.0.0" prosemirror-keymap "^1.0.0"
prosemirror-model "^1.0.0" prosemirror-model "^1.0.0"
@ -9995,49 +9995,49 @@ prosemirror-gapcursor@^1.0.4:
prosemirror-view "^1.0.0" prosemirror-view "^1.0.0"
prosemirror-history@^1.0.4: prosemirror-history@^1.0.4:
version "1.1.1" version "1.1.2"
resolved "https://registry.yarnpkg.com/prosemirror-history/-/prosemirror-history-1.1.1.tgz#40edb4ec33a1e9424557a83044dc664f083c7650" resolved "https://registry.yarnpkg.com/prosemirror-history/-/prosemirror-history-1.1.2.tgz#3e8f11efbd316e98322028be67549df1f94fc6da"
integrity sha512-sIj66w2hNKs5+FFecpnH13xkOGlcK3dOFnM+d9BZjF0jxSxBTwjYjfiYm9q62DoFlSAGSai5P3IqnUsyBJ8iyw== integrity sha512-erhxYS5gm/6MiXP8jUoJBgc8IbaqjHDVPl9KGg5JrMZOSSOwHv85+4Fb0Q7sYtv2fYwAjOSw/kSA9vkxJ6wOwA==
dependencies: dependencies:
prosemirror-state "^1.2.2" prosemirror-state "^1.2.2"
prosemirror-transform "^1.0.0" prosemirror-transform "^1.0.0"
rope-sequence "^1.3.0" rope-sequence "^1.3.0"
prosemirror-inputrules@^1.0.4: prosemirror-inputrules@^1.0.4:
version "1.1.1" version "1.1.2"
resolved "https://registry.yarnpkg.com/prosemirror-inputrules/-/prosemirror-inputrules-1.1.1.tgz#fc00ee44f09874b3b7a0a6650be6a3ea5672e9f6" resolved "https://registry.yarnpkg.com/prosemirror-inputrules/-/prosemirror-inputrules-1.1.2.tgz#487e46c763e1212a4577397aba7706139084f012"
integrity sha512-UWuLz9anIW/KN2nSXKx+7sHSNSEObnPX8jD9THaWRn+C0xejJAJikMlVqIi/QlVH8ET0Hqx/qbXaM5Q4SV33tA== integrity sha512-Ja5Z3BWestlHYGvtSGqyvxMeB8QEuBjlHM8YnKtLGUXMDp965qdDV4goV8lJb17kIWHk7e7JNj6Catuoa3302g==
dependencies: dependencies:
prosemirror-state "^1.0.0" prosemirror-state "^1.0.0"
prosemirror-transform "^1.0.0" prosemirror-transform "^1.0.0"
prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.0.2: prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.0.2:
version "1.1.2" version "1.1.3"
resolved "https://registry.yarnpkg.com/prosemirror-keymap/-/prosemirror-keymap-1.1.2.tgz#ec83b1b01d36d6e4968e24d4d0c866f424bd532b" resolved "https://registry.yarnpkg.com/prosemirror-keymap/-/prosemirror-keymap-1.1.3.tgz#be22d6108df2521608e9216a87b1a810f0ed361e"
integrity sha512-y80SvHPGaKJ4+6cIydDjOYmy6V9DQOo/BPJ14oGfzzQ5+VdFf/W/B6CT9AIAha6uOnpC3bdYY01XU7JmMge3TA== integrity sha512-PRA4NzkUMzV/NFf5pyQ6tmlIHiW/qjQ1kGWUlV2rF/dvlOxtpGpTEjIMhWgLuMf+HiDEFnUEP7uhYXu+t+491g==
dependencies: dependencies:
prosemirror-state "^1.0.0" prosemirror-state "^1.0.0"
w3c-keyname "^2.2.0" w3c-keyname "^2.2.0"
prosemirror-model@^1.0.0, prosemirror-model@^1.1.0, prosemirror-model@^1.7.4: prosemirror-model@^1.0.0, prosemirror-model@^1.1.0, prosemirror-model@^1.7.4:
version "1.8.1" version "1.8.2"
resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.8.1.tgz#44669d6b9dc84a69e4a7b54b77f12905d2f55250" resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.8.2.tgz#c74eaacb0bbfea49b59a6d89fef5516181666a56"
integrity sha512-mpXHJQ99NllmQ4Kz3PSTc1j79iiBqpJWWAib4OPiZUlYSvcj3+nolBbRFWUjpZ1MRELWAjHKPBEzzhQ4nB6vFg== integrity sha512-piffokzW7opZVCjf/9YaoXvTC0g7zMRWKJib1hpphPfC+4x6ZXe5CiExgycoWZJe59VxxP7uHX8aFiwg2i9mUQ==
dependencies: dependencies:
orderedmap "^1.1.0" orderedmap "^1.1.0"
prosemirror-schema-list@^1.0.4: prosemirror-schema-list@^1.0.4:
version "1.1.1" version "1.1.2"
resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.1.1.tgz#bec2c9cf6929995bbf0cb09cb3e90c1ba07cb4a1" resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.1.2.tgz#310809209094b03425da7f5c337105074913da6c"
integrity sha512-8bFd3maQIOiGpRCkijfd9NiZvQqP8TVYQWSwnkb2FVHFsqdw22l1d42rtG9LHvSGh64KIdOpfh48HnqpVxsHIg== integrity sha512-dgM9PwtM4twa5WsgSYMB+J8bwjnR43DAD3L9MsR9rKm/nZR5Y85xcjB7gusVMSsbQ2NomMZF03RE6No6mTnclQ==
dependencies: dependencies:
prosemirror-model "^1.0.0" prosemirror-model "^1.0.0"
prosemirror-transform "^1.0.0" prosemirror-transform "^1.0.0"
prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.2.4: prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.2.4:
version "1.3.1" version "1.3.2"
resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.3.1.tgz#108ac86ab7f5ac228bf16a214c36262998aee53b" resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.3.2.tgz#1b910b0dc01c1f00926bb9ba1589f7b7ac0d658b"
integrity sha512-xECWkjVtj7/qaM3u80dBbL7mGUCUe1TFRxIEaNQKnNYCI2zwSbS0AnIWuLRaHHcZ9GXv+7NxTHDh3MOyxahVkA== integrity sha512-t/JqE3aR0SV9QrzFVkAXsQwsgrQBNs/BDbcFH20RssW0xauqNNdjTXxy/J/kM7F+0zYi6+BRmz7cMMQQFU3mwQ==
dependencies: dependencies:
prosemirror-model "^1.0.0" prosemirror-model "^1.0.0"
prosemirror-transform "^1.0.0" prosemirror-transform "^1.0.0"
@ -10054,9 +10054,9 @@ prosemirror-tables@^0.9.5:
prosemirror-view "^1.0.0" prosemirror-view "^1.0.0"
prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.1.5: prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.1.5:
version "1.2.1" version "1.2.2"
resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.2.1.tgz#ada1e5f2fbb5214e798d55005798de15fdd8b7ac" resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.2.2.tgz#4439ae7e88ea1395d9beed6a4cd852d72b16ed2f"
integrity sha512-ORDd/+MBBwQnuzNbT5XyS6saC2MZqxagwdnqfDxt2PoT5NhvC8Fohh8c+B7K/0ij4eVGRsifQKti3diFlvDFAg== integrity sha512-expO11jAsxaHk2RdZtzPsumc1bAAZi4UiXwTLQbftsdnIUWZE5Snyag595p1lx/B8QHUZ6tYWWOaOkzXKoJmYw==
dependencies: dependencies:
prosemirror-model "^1.0.0" prosemirror-model "^1.0.0"
@ -10066,9 +10066,9 @@ prosemirror-utils@^0.9.6:
integrity sha512-UC+j9hQQ1POYfMc5p7UFxBTptRiGPR7Kkmbl3jVvU8VgQbkI89tR/GK+3QYC8n+VvBZrtAoCrJItNhWSxX3slA== integrity sha512-UC+j9hQQ1POYfMc5p7UFxBTptRiGPR7Kkmbl3jVvU8VgQbkI89tR/GK+3QYC8n+VvBZrtAoCrJItNhWSxX3slA==
prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.11.7: prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.11.7:
version "1.13.3" version "1.13.4"
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.13.3.tgz#3b6767ea732b3315b583d37b04c966515caf4823" resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.13.4.tgz#01d873db7731e0aacc410a9038447d1b7536fd07"
integrity sha512-5AjTEoSgCD0RfETVfo1QLMa8qsb5Ogzf5B6b8JaSpEi3NAnfVxBwIhbExd9vrJ7SiRWn1ZoP7welx5a5b1YLaA== integrity sha512-mtgWEK16uYQFk3kijRlkSpAmDuy7rxYuv0pgyEBDmLT1PCPY8380CoaYnP8znUT6BXIGlJ8oTveK3M50U+B0vw==
dependencies: dependencies:
prosemirror-model "^1.1.0" prosemirror-model "^1.1.0"
prosemirror-state "^1.0.0" prosemirror-state "^1.0.0"

View File

@ -34,6 +34,21 @@ defmodule Mobilizon.Config do
def instance_user_agent, def instance_user_agent,
do: "#{instance_name()} #{instance_hostname()} - Mobilizon #{Mix.Project.config()[:version]}" do: "#{instance_name()} #{instance_hostname()} - Mobilizon #{Mix.Project.config()[:version]}"
@spec instance_geocoding_provider :: atom()
def instance_geocoding_provider,
do: get_in(Application.get_env(:mobilizon, Mobilizon.Service.Geospatial), [:service])
@spec instance_geocoding_autocomplete :: boolean
def instance_geocoding_autocomplete,
do: instance_geocoding_provider() !== Mobilizon.Service.Geospatial.Nominatim
@spec instance_maps_tiles_endpoint :: String.t()
def instance_maps_tiles_endpoint, do: Application.get_env(:mobilizon, :maps)[:tiles][:endpoint]
@spec instance_maps_tiles_attribution :: String.t()
def instance_maps_tiles_attribution,
do: Application.get_env(:mobilizon, :maps)[:tiles][:attribution]
@spec get(module | atom) :: any @spec get(module | atom) :: any
def get(key), do: get(key, nil) def get(key), do: get(key, nil)

View File

@ -32,7 +32,17 @@ defmodule MobilizonWeb.Resolvers.Config do
registrations_open: Config.instance_registrations_open?(), registrations_open: Config.instance_registrations_open?(),
description: Config.instance_description(), description: Config.instance_description(),
location: location, location: location,
country_code: country_code country_code: country_code,
geocoding: %{
provider: Config.instance_geocoding_provider(),
autocomplete: Config.instance_geocoding_autocomplete()
},
maps: %{
tiles: %{
endpoint: Config.instance_maps_tiles_endpoint(),
attribution: Config.instance_maps_tiles_attribution()
}
}
}} }}
end end
end end

View File

@ -15,6 +15,8 @@ defmodule MobilizonWeb.Schema.ConfigType do
field(:registrations_open, :boolean) field(:registrations_open, :boolean)
field(:country_code, :string) field(:country_code, :string)
field(:location, :lonlat) field(:location, :lonlat)
field(:geocoding, :geocoding)
field(:maps, :maps)
end end
object :lonlat do object :lonlat do
@ -23,6 +25,20 @@ defmodule MobilizonWeb.Schema.ConfigType do
field(:accuracy_radius, :integer) field(:accuracy_radius, :integer)
end end
object :geocoding do
field(:autocomplete, :boolean)
field(:provider, :string)
end
object :maps do
field(:tiles, :tiles)
end
object :tiles do
field(:endpoint, :string)
field(:attribution, :string)
end
object :config_queries do object :config_queries do
@desc "Get the instance config" @desc "Get the instance config"
field :config, :config do field :config, :config do

View File

@ -29,6 +29,8 @@ defmodule Mobilizon.Service.Geospatial.Addok do
HTTPoison.get(url, headers), HTTPoison.get(url, headers),
{:ok, %{"features" => features}} <- Poison.decode(body) do {:ok, %{"features" => features}} <- Poison.decode(body) do
process_data(features) process_data(features)
else
_ -> []
end end
end end
@ -47,6 +49,8 @@ defmodule Mobilizon.Service.Geospatial.Addok do
HTTPoison.get(url, headers), HTTPoison.get(url, headers),
{:ok, %{"features" => features}} <- Poison.decode(body) do {:ok, %{"features" => features}} <- Poison.decode(body) do
process_data(features) process_data(features)
else
_ -> []
end end
end end

View File

@ -32,6 +32,8 @@ defmodule Mobilizon.Service.Geospatial.Mimirsbrunn do
HTTPoison.get(url, headers), HTTPoison.get(url, headers),
{:ok, %{"features" => features}} <- Poison.decode(body) do {:ok, %{"features" => features}} <- Poison.decode(body) do
process_data(features) process_data(features)
else
_ -> []
end end
end end
@ -50,6 +52,8 @@ defmodule Mobilizon.Service.Geospatial.Mimirsbrunn do
HTTPoison.get(url, headers), HTTPoison.get(url, headers),
{:ok, %{"features" => features}} <- Poison.decode(body) do {:ok, %{"features" => features}} <- Poison.decode(body) do
process_data(features) process_data(features)
else
_ -> []
end end
end end

View File

@ -29,6 +29,8 @@ defmodule Mobilizon.Service.Geospatial.Nominatim do
HTTPoison.get(url, headers), HTTPoison.get(url, headers),
{:ok, %{"features" => features}} <- Poison.decode(body) do {:ok, %{"features" => features}} <- Poison.decode(body) do
features |> process_data() |> Enum.filter(& &1) features |> process_data() |> Enum.filter(& &1)
else
_ -> []
end end
end end
@ -47,6 +49,8 @@ defmodule Mobilizon.Service.Geospatial.Nominatim do
HTTPoison.get(url, headers), HTTPoison.get(url, headers),
{:ok, %{"features" => features}} <- Poison.decode(body) do {:ok, %{"features" => features}} <- Poison.decode(body) do
features |> process_data() |> Enum.filter(& &1) features |> process_data() |> Enum.filter(& &1)
else
_ -> []
end end
end end

View File

@ -30,6 +30,8 @@ defmodule Mobilizon.Service.Geospatial.Pelias do
HTTPoison.get(url, headers), HTTPoison.get(url, headers),
{:ok, %{"features" => features}} <- Poison.decode(body) do {:ok, %{"features" => features}} <- Poison.decode(body) do
process_data(features) process_data(features)
else
_ -> []
end end
end end
@ -48,6 +50,8 @@ defmodule Mobilizon.Service.Geospatial.Pelias do
HTTPoison.get(url, headers), HTTPoison.get(url, headers),
{:ok, %{"features" => features}} <- Poison.decode(body) do {:ok, %{"features" => features}} <- Poison.decode(body) do
process_data(features) process_data(features)
else
_ -> []
end end
end end

View File

@ -30,6 +30,8 @@ defmodule Mobilizon.Service.Geospatial.Photon do
HTTPoison.get(url, headers), HTTPoison.get(url, headers),
{:ok, %{"features" => features}} <- Poison.decode(body) do {:ok, %{"features" => features}} <- Poison.decode(body) do
process_data(features) process_data(features)
else
_ -> []
end end
end end
@ -48,6 +50,8 @@ defmodule Mobilizon.Service.Geospatial.Photon do
HTTPoison.get(url, headers), HTTPoison.get(url, headers),
{:ok, %{"features" => features}} <- Poison.decode(body) do {:ok, %{"features" => features}} <- Poison.decode(body) do
process_data(features) process_data(features)
else
_ -> []
end end
end end

View File

@ -1,5 +1,5 @@
# source: http://localhost:4000/api # source: http://localhost:4000/api
# timestamp: Mon Nov 18 2019 16:00:35 GMT+0100 (Central European Standard Time) # timestamp: Wed Nov 20 2019 10:45:54 GMT+0100 (Central European Standard Time)
schema { schema {
query: RootQueryType query: RootQueryType
@ -191,7 +191,9 @@ enum CommentVisibility {
type Config { type Config {
countryCode: String countryCode: String
description: String description: String
geocoding: Geocoding
location: Lonlat location: Lonlat
maps: Maps
name: String name: String
registrationsOpen: Boolean registrationsOpen: Boolean
} }
@ -531,6 +533,11 @@ type Follower {
targetActor: Actor targetActor: Actor
} }
type Geocoding {
autocomplete: Boolean
provider: String
}
""" """
Represents a group of actors Represents a group of actors
@ -639,6 +646,10 @@ type Lonlat {
longitude: Float longitude: Float
} }
type Maps {
tiles: Tiles
}
""" """
Represents a member of a group Represents a member of a group
@ -1229,6 +1240,11 @@ type Tag {
title: String title: String
} }
type Tiles {
attribution: String
endpoint: String
}
""" """
Represents an uploaded file. Represents an uploaded file.