Linked events
Linked Events provides categorized data on events and places. The project was originally developed for the City of Helsinki.
The Linked Events API for the Helsinki capital region contains data from the Helsinki City Tourist & Convention Bureau, the City of Helsinki Cultural Office and the Helmet metropolitan area public libraries.
Linked Events has been updated to Django 1.11. To upgrade to Linked Events release v2.0, please upgrade to release v1.3 first.
Set up project with Docker
-
Create
local_settings.py
from the template:cp local_settings.py.template local_settings.py
-
Run
docker-compose up
-
Run migrations:
docker exec linkedevents-backend python manage.py migrate
-
Syncronize languages for translations in DB:
docker exec -it linkedevents-backend python manage.py sync_translation_fields
- Answer
y
(for 'yes') to all prompt questions
-
Import some data for testing:
# Import general Finnish ontology (used by events from following sources) docker exec -it linkedevents-backend python manage.py event_import yso --all # Import places from Helsinki metropolitan region service registry (used by events from following sources) docker exec -it linkedevents-backend python manage.py event_import tprek --places # Import events from Visit Helsinki docker exec -it linkedevents-backend python manage.py event_import matko --events # Import events from Helsinki metropolitan region libraries docker exec -it linkedevents-backend python manage.py event_import helmet --events # Import events from Espoo docker exec -it linkedevents-backend python manage.py event_import espoo --events
-
Update search indexes:
docker exec -it linkedevents-backend python manage.py rebuild_index
-
(Optionally) install API frontend templates:
docker exec -it linkedevents-backend python manage.py install_templates helevents
-
Start your Django server:
docker exec -it linkedevents-backend python manage.py runserver 0:8000
Now your project is live at localhost:8000
Installation for development
These instructions assume an $INSTALL_BASE, like so:
INSTALL_BASE=$HOME/linkedevents
If you've already cloned this repository, just move repository root into $INSTALL_BASE/linkedevents. Otherwise just clone the repository, like so:
git clone https://github.com/City-of-Helsinki/linkedevents.git $INSTALL_BASE/linkedevents
Prepare Python 3.x virtualenv using your favorite tools and activate it. Plain virtualenv is like so:
virtualenv -p python3 $INSTALL_BASE/venv
source $INSTALL_BASE/venv/bin/activate
Install required Python packages into the virtualenv
cd $INSTALL_BASE/linkedevents
pip install -r requirements.txt
Create the database, like so: (we have only tested on PostgreSQL)
cd $INSTALL_BASE/linkedevents
sudo -u postgres createuser -R -S linkedevents
# Following is for US locale, we are not certain whether Linkedevents
# behaves differently depending on DB collation & ctype
#sudo -u postgres createdb -Olinkedevents linkedevents
# This is is for Finnish locale
sudo -u postgres createdb -Olinkedevents -Ttemplate0 -lfi_FI.UTF-8 linkedevents
# Create extensions in the database
sudo -u postgres psql linkedevents -c "CREATE EXTENSION postgis;"
sudo -u postgres psql linkedevents -c "CREATE EXTENSION hstore;"
# This fills the database with a basic skeleton
python manage.py migrate
# This adds language fields based on settings.LANGUAGES (which may be missing in external dependencies)
python manage.py sync_translation_fields
You probably want to import some data for testing (these are events around Helsinki), like so:
cd $INSTALL_BASE/linkedevents
# Import general Finnish ontology (used by events from following sources)
python manage.py event_import yso --all
# Import places from Helsinki metropolitan region service registry (used by events from following sources)
python manage.py event_import tprek --places
# Import events from Visit Helsinki
python manage.py event_import matko --events
# Import events from Helsinki metropolitan region libraries
python manage.py event_import helmet --events
# Import events from Espoo
python manage.py event_import espoo --events
Furthermore, you may install city-specific HTML page templates for the browsable API by
cd $INSTALL_BASE/linkedevents
python manage.py install_templates helevents
This will install the helevents/templates/rest_framework/api.html
template,
which contains Helsinki event data summary and license. Customize the template
for your favorite city by creating your_favorite_city/templates/rest_framework/api.html
.
For further erudition, take a look at the DRF documentation on customizing the browsable API
After this, everything but search endpoint (/search) is working. See search
Production notes
Development installation above will give you quite a serviceable production installation for lightish usage. You can serve out the application using your favorite WSGI-capable application server. The WSGI-entrypoint for Linked Events is linkedevents.wsgi
or in file linkedevents/wsgi.py
. Former is used by gunicorn, latter by uwsgi. The callable is application
.
You will also need to serve out static
and media
folders at /static
and /media
in your URL space.
Running tests
Tests must be run using an user who can create (and drop) databases and write the directories your linkedevents installation resides in. Also the template database must include Postgis and HSTORE-extensions. If you are developing, you probably want to give those permissions to the database user configured in your development instance. Like so:
# Change this if you have different DB user
DATABASE_USER=linkedevents
# Most likely you have a postgres system user that can log into postgres as DB postgres user
sudo -u postgres psql << EOF
ALTER USER "$DATABASE_USER" CREATEDB;
\c template1
CREATE EXTENSION IF NOT EXISTS postgis;
CREATE EXTENSION IF NOT EXISTS hstore;
EOF
Afterwards you can run the tests:
cd $INSTALL_BASE/linkedevents
py.test events
Note that search tests will fail unless you configure search
Requirements
Linked Events uses two files for requirements. The workflow is as follows.
requirements.txt
is not edited manually, but is generated
with pip-compile
.
requirements.txt
always contains fully tested, pinned versions
of the requirements. requirements.in
contains the primary, unpinned
requirements of the project without their dependencies.
In production, deployments should always use requirements.txt
and the versions pinned therein. In development, new virtualenvs
and development environments should also be initialised using
requirements.txt
. pip-sync
will synchronize the active
virtualenv to match exactly the packages in requirements.txt
.
In development and testing, to update to the latest versions
of requirements, use the command pip-compile
. You can
use requires.io to monitor the
pinned versions for updates.
To remove a dependency, remove it from requirements.in
,
run pip-compile
and then pip-sync
. If everything works
as expected, commit the changes.
Search
Linkedevents uses Elasticsearch for generating results on the /search-endpoint. If you wish to use that functionality, proceed like so:
-
Install elasticsearch
We've only tested using the rather ancient 1.7 version. Version 5.x will certainly not work as the
django-haystack
-library does not support it. If you are using Ubuntu 16.04, 1.7 will be available in the official repository. -
(For finnish support) Install elasticsearch-analyzer-voikko, libvoikko and needed dictionaries
/usr/share/elasticsearch/bin/plugin -i fi.evident.elasticsearch/elasticsearch-analysis-voikko/0.4.0
This specific command is for Debian derivatives. The path toplugin
command might be different on yours. Note that version 0.4.0 is the one compatible with Elasticsearch 1.7Installing libvoikko:
apt-get install libvoikko1
Installing the dictionaries (v5 dictionaries are needed for libvoikko version included in Ubuntu 16.04):
wget -P $INSTALL_BASE http://www.puimula.org/htp/testing/voikko-snapshot-v5/dict-morpho.zip unzip $INSTALL_BASE/dict-morpho.zip -d /etc/voikko ```
-
Configure the thing
Add the long block below these instructions to $INSTALL_BASE/linkedevents/local_settings.py. If you are familiar with Django haystack, feel free to customize it.
-
Rebuild the search indexes
python manage.py rebuild_index
You should now have a working /search endpoint, give or take a few.
CUSTOM_MAPPINGS = {
'autosuggest': {
'search_analyzer': 'standard',
'index_analyzer': 'edgengram_analyzer',
'analyzer': None
},
'text': {
'analyzer': 'default'
}
}
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'multilingual_haystack.backends.MultilingualSearchEngine',
},
'default-fi': {
'ENGINE': 'multilingual_haystack.backends.LanguageSearchEngine',
'BASE_ENGINE': 'events.custom_elasticsearch_search_backend.CustomEsSearchEngine',
'URL': 'http://localhost:9200/',
'INDEX_NAME': 'linkedevents-fi',
'MAPPINGS': CUSTOM_MAPPINGS,
'SETTINGS': {
"analysis": {
"analyzer": {
"default": {
"tokenizer": "finnish",
"filter": ["lowercase", "voikko_filter"]
}
},
"filter": {
"voikko_filter": {
"type": "voikko",
}
}
}
}
},
'default-sv': {
'ENGINE': 'multilingual_haystack.backends.LanguageSearchEngine',
'BASE_ENGINE': 'events.custom_elasticsearch_search_backend.CustomEsSearchEngine',
'URL': 'http://localhost:9200/',
'INDEX_NAME': 'linkedevents-sv',
'MAPPINGS': CUSTOM_MAPPINGS
},
'default-en': {
'ENGINE': 'multilingual_haystack.backends.LanguageSearchEngine',
'BASE_ENGINE': 'events.custom_elasticsearch_search_backend.CustomEsSearchEngine',
'URL': 'http://localhost:9200/',
'INDEX_NAME': 'linkedevents-en',
'MAPPINGS': CUSTOM_MAPPINGS
},
}
Event extensions
It is possible to extend event data and API without touching events
application by implementing separate extension applications. These extensions will be wired under field extension_<extension idenfier>
in event API. If not auto enabled (see 6. below), extensions can be enabled per request using query param extensions
with comma separated identifiers as values, or all
for enabling all the extensions.
To implement an extension:
-
Create a new Django application, preferably named
extension_<unique identifier for the extension>
. -
If you need to add new data for events, implement that using model(s) in the extension application.
-
Inherit
events.extensions.EventExtension
and implement needed attributes and methods. See extensions.py for details. -
Add
event_extension: <your EventExtension subclass>
attribute to the extension applications'sAppConfig
. -
Make the extension available by adding the extension application to
INSTALLED_APPS
. -
If you want to force the extension to be enabled on every request, add the extension's identifier to
AUTO_ENABLED_EXTENSIONS
in Django settings.
For an example extension implementation, see course extension.