compute initial content for dashboard (#32064)

This commit is contained in:
Frédéric Péters 2019-05-26 11:03:29 +02:00
parent 82e5f6ee74
commit 8d97d2d908
4 changed files with 98 additions and 89 deletions

View File

@ -27,9 +27,6 @@ class AppConfig(django.apps.AppConfig):
name = __name__
verbose_name = _('GNM Extension')
def ready(self):
from . import signals
def get_before_urls(self):
from . import urls
return urls.urlpatterns

View File

@ -1,34 +0,0 @@
# -*- coding: utf-8 -*-
# combo-plugin-gnm - Combo GNM plugin
# Copyright (C) 2017-2019 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.db.models.signals import post_save
from django.dispatch import receiver
from combo.middleware import get_request
from combo.profile.models import Profile
@receiver(post_save, sender=Profile)
def new_profile(sender, instance=None, created=False, **kwargs):
if not created:
return
request = get_request()
saml_info = request.session.get('mellon_session', {})
if False:
# if profile has an address push it to the favourite places datastore
saml_info['address'][0]
# fill dashboard with suggestions

View File

@ -24,6 +24,7 @@ import random
import re
from dateutil.parser import parse as dateutil_parse
from pyproj import Geod
from requests import RequestException
from django import template
@ -37,7 +38,7 @@ from django.utils.text import slugify
from django.utils.timezone import is_naive, make_aware
from django.utils.safestring import mark_safe
from combo.apps.dashboard.models import DashboardCell
from combo.apps.dashboard.models import DashboardCell, Tile
from combo.apps.maps.models import Map, MapLayer
from combo.data.models import Page, CellBase, ConfigJsonCell
from combo.public.views import render_cell
@ -509,8 +510,29 @@ def as_commune(user_data):
@register.assignment_tag
def get_suggestions(request, cell, user_data, places_data):
tile_data = []
def get_suggestions(request, user_data, places_data):
# fill initial dashboard based on this layout:
## au quotidien
# mairie tile
# closest velov/tcl/swimming pool/etc. tiles
## environnement
# air quality
# pollen
if not getattr(request, 'user', None) or not request.user.is_authenticated():
# no user
return ['no user']
dashboard = DashboardCell.objects.all().filter(page__snapshot__isnull=True)[0]
if Tile.objects.filter(dashboard=dashboard, user=request.user).exists():
# dashboard already filled
return ['already filled']
mairie_tile = None
service_tiles = []
airquality_tile = {'key': 'airquality', 'parameters': settings.COMBO_MAP_DEFAULT_POSITION}
pollen_tile = {'key': 'pollen'}
addresses = []
city = user_data.get('city') or user_data.get('address_city')
if city:
@ -528,42 +550,38 @@ def get_suggestions(request, cell, user_data, places_data):
if 'Annexe' in feature['properties']['nom']:
continue
if city_slug in slugify(feature['properties']['nom']):
tile_data.append({'key': maplayer.slug,
'properties': feature['properties']})
mairie_tile = {'key': maplayer.slug, 'properties': feature['properties']}
break
if random.random() < 0.3:
tile_data.append({'key': 'airquality'})
if random.random() < 0.1:
tile_data.append({'key': 'pollen'})
if user_data.get('address_street'):
address = None
if places_data and places_data.get('data'):
place_data = places_data['data'][0]
address = u'%(adresse)s, %(ville)s, France' % place_data['content']
elif user_data.get('address_street'):
if not user_data.get('address_number'):
user_data['address_number'] = ''
addresses.append(u'%(address_number)s %(address_street)s, %(address_city)s, France' % user_data)
address = u'%(address_number)s %(address_street)s, %(address_city)s, France' % user_data
if places_data:
for place_data in places_data.get('data'):
addresses.append(u'%(adresse)s, %(ville)s, France' % place_data['content'])
coords = []
nominatim_url = 'https://nominatim.entrouvert.org'
for address in addresses:
coords = None
if address:
nominatim_url = settings.COMBO_GEOCODING_SERVICE
url = '%s/search?q=%s&accept-language=fr&format=json' % (
nominatim_url, quote(address.encode('utf-8')))
try:
search_result = requests.get(url, timeout=2, without_user=True,
cache_duration=300).json()
except RequestException:
continue
if not search_result:
continue
coords.append({'lon': search_result[0]['lon'], 'lat': search_result[0]['lat']})
pass
if search_result:
coords = {'lon': search_result[0]['lon'], 'lat': search_result[0]['lat']}
for coord in coords:
lat1, lat2 = float(coord['lat']) - 0.008, float(coord['lat']) + 0.008
lon1, lon2 = float(coord['lon']) - 0.006, float(coord['lon']) + 0.006
for maplayer in MapLayer.objects.filter(slug__in=('velov', 'piscine', 'tcl')):
if coords:
airquality_tile = {'key': 'airquality', 'parameters': coords}
lat1, lat2 = float(coords['lat']) - 0.008, float(coords['lat']) + 0.008
lon1, lon2 = float(coords['lon']) - 0.006, float(coords['lon']) + 0.006
geod = Geod(ellps='WGS84')
for maplayer in MapLayer.objects.filter(slug__in=('velov', 'piscine', 'tcl', 'bibliotheque', 'mdr')):
url = maplayer.geojson_url + '&BBOX=%s,%s,%s,%s' % (lat1, lon1, lat2, lon2)
try:
data_result = requests.get(url, timeout=2, without_user=True,
@ -574,34 +592,54 @@ def get_suggestions(request, cell, user_data, places_data):
if not features:
continue
for feature in features:
# thanks to the flat earth society
feature['distance'] = math.sqrt(
(float(coord['lon']) - feature['geometry']['coordinates'][0])**2 +
(float(coord['lat']) - feature['geometry']['coordinates'][1])**2)
feature['distance'] = geod.inv(
float(coords['lon']),
float(coords['lat']),
float(feature['geometry']['coordinates'][0]),
float(feature['geometry']['coordinates'][1]))[2]
features.sort(key=lambda x: x['distance'])
# take two closest features
for feature in features[:2]:
tile_data.append({'key': maplayer.slug, 'properties': feature['properties']})
# take closest feature
if features:
service_tiles.append({'key': maplayer.slug, 'properties': features[0]['properties']})
dashboard = DashboardCell.objects.all()[0]
cells = []
seen = {}
for data in tile_data:
cell = ConfigJsonCell(key=data['key'], order=1,
page_id=cell.page_id, placeholder='_auto_tile')
cell_form_keys = [x['varname'] for x in settings.JSON_CELL_TYPES[cell.key].get('form') or {}]
cell.parameters = {}
for key in cell_form_keys:
cell.parameters[key] = data['properties'].get(key)
cell_uid = repr((data['key'], cell.parameters))
if cell_uid in seen:
continue
seen[cell_uid] = True
tiles = []
if mairie_tile or service_tiles:
tiles.append({'key': 'group-title', 'parameters': {'text': 'Au quotidien'}})
if mairie_tile:
tiles.append(mairie_tile)
if service_tiles:
random.shuffle(service_tiles)
tiles.extend(service_tiles)
if airquality_tile or pollen_tile:
tiles.append({'key': 'group-title', 'parameters': {'text': 'Environnement'}})
if airquality_tile:
tiles.append(airquality_tile)
if pollen_tile:
tiles.append(pollen_tile)
for i, tile_data in enumerate(tiles):
if 'properties' in tile_data:
cell_form_keys = [x['varname'] for x in settings.JSON_CELL_TYPES[tile_data['key']].get('form') or {}]
tile_data['parameters'] = {}
for key in cell_form_keys:
tile_data['parameters'][key] = tile_data['properties'].get(key)
cell = ConfigJsonCell(
key=tile_data['key'],
parameters=tile_data.get('parameters', {}),
order=0,
page_id=dashboard.page_id,
placeholder='_suggested_tile')
cell.save()
cells.append(render_cell(request, cell=cell).content)
tile = Tile(
dashboard=dashboard,
cell=cell,
user=request.user,
order=i+1)
tile.save()
random.shuffle(cells)
return cells[:5]
return tiles
@register.assignment_tag
def get_gnm_portal_url():

10
debian/50gnm.py vendored
View File

@ -8,6 +8,7 @@ MELLON_ADD_AUTHNREQUEST_NEXT_URL_EXTENSION = True
COMBO_MAP_TILE_URLTEMPLATE = "https://tiles.entrouvert.org/hdm/{z}/{x}/{y}.png"
COMBO_MAP_ATTRIBUTION = "&copy; <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a>"
COMBO_GEOCODING_SERVICE = 'https://nominatim.entrouvert.org'
COMBO_DASHBOARD_ENABLED = True
COMBO_DASHBOARD_NEW_TILE_POSITION = 'first'
@ -248,6 +249,12 @@ JSON_CELL_TYPES = {
"name": u"Lieux favoris",
"force_async": False,
"cache_duration": 600,
"additional-data": [
{
"key": "userdata",
"url": "[idp_url]api/users/[user_nameid]/"
}
],
"actions": {
"create": {
"url": "[passerelle_url]jsondatastore/lieux-favoris/data/create?name_id=[user_nameid]"
@ -314,7 +321,8 @@ JSON_CELL_TYPES = {
"suggestions": {
"name": "Suggestions",
"url": "[idp_url]api/users/[user_nameid]/",
"loading-message": "Recherche de suggestions…",
"force_async": True,
"loading-message": "Assemblage en cours, quelques secondes…",
"additional-data": [
{"key": "places",
"url": "[passerelle_url]jsondatastore/lieux-favoris/data/?name_id=[user_nameid]"