diff --git a/tests/admin_pages/test_datasource.py b/tests/admin_pages/test_datasource.py
index 43a00561c..87a1e8587 100644
--- a/tests/admin_pages/test_datasource.py
+++ b/tests/admin_pages/test_datasource.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import json
+import mock
import os
import xml.etree.ElementTree as ET
@@ -111,6 +112,7 @@ def test_data_sources_agenda_without_chrono(pub):
resp = app.get('/backoffice/settings/data-sources/')
assert 'Agendas' not in resp.text
assert 'There are no data sources from agendas.' not in resp.text
+ assert 'sync-agendas' not in resp.text
def test_data_sources_agenda(pub, chrono_url):
@@ -121,6 +123,7 @@ def test_data_sources_agenda(pub, chrono_url):
resp = app.get('/backoffice/settings/data-sources/')
assert 'Agendas' in resp.text
assert 'There are no agendas.' in resp.text
+ assert 'sync-agendas' in resp.text
data_source = NamedDataSource(name='foobar')
data_source.data_source = {'type': 'json', 'value': 'http://some.url'}
@@ -614,3 +617,19 @@ def test_data_sources_in_use_edit_slug(pub):
resp = resp.click(href='edit')
assert 'form_slug' in resp.text
resp = resp.form.submit('submit')
+
+
+@mock.patch('wcs.data_sources.collect_agenda_data')
+def test_data_sources_agenda_refresh(mock_collect, pub, chrono_url):
+ create_superuser(pub)
+ NamedDataSource.wipe()
+
+ mock_collect.return_value = [
+ {'text': 'Events A', 'url': 'http://chrono.example.net/api/agenda/events-A/datetimes/'},
+ {'text': 'Events B', 'url': 'http://chrono.example.net/api/agenda/events-B/datetimes/'},
+ ]
+
+ app = login(get_app(pub))
+ resp = app.get('/backoffice/settings/data-sources/sync-agendas')
+ assert resp.location == 'http://example.net/backoffice/settings/data-sources/'
+ assert NamedDataSource.count() == 2
diff --git a/wcs/admin/data_sources.py b/wcs/admin/data_sources.py
index 5046f3975..d835aa701 100644
--- a/wcs/admin/data_sources.py
+++ b/wcs/admin/data_sources.py
@@ -32,7 +32,13 @@ from wcs.qommon.form import get_session
from wcs.qommon import misc
from wcs.qommon.backoffice.menu import html_top
from wcs.carddef import CardDef
-from wcs.data_sources import NamedDataSource, DataSourceSelectionWidget, get_structured_items, has_chrono
+from wcs.data_sources import (
+ NamedDataSource,
+ DataSourceSelectionWidget,
+ get_structured_items,
+ has_chrono,
+ RefreshAgendas,
+)
from wcs.formdef import FormDef, get_formdefs_of_all_kinds
from wcs.backoffice.snapshots import SnapshotsDirectory
@@ -364,7 +370,7 @@ class NamedDataSourcePage(Directory):
class NamedDataSourcesDirectory(Directory):
- _q_exports = ['', 'new', ('import', 'p_import')]
+ _q_exports = ['', 'new', ('import', 'p_import'), ('sync-agendas', 'sync_agendas')]
def _q_traverse(self, path):
get_response().breadcrumb.append(('data-sources/', _('Data Sources')))
@@ -463,3 +469,8 @@ class NamedDataSourcesDirectory(Directory):
datasource.slug = None # a new one will be set in .store()
datasource.store()
return redirect('%s/' % datasource.id)
+
+ def sync_agendas(self):
+ get_response().add_after_job(RefreshAgendas())
+ get_session().message = ('info', _('Agendas will be updated in the background.'))
+ return redirect('.')
diff --git a/wcs/data_sources.py b/wcs/data_sources.py
index 95978635e..9ca96beee 100644
--- a/wcs/data_sources.py
+++ b/wcs/data_sources.py
@@ -27,7 +27,7 @@ from django.utils.six.moves.urllib import parse as urlparse
from quixote import get_publisher, get_request, get_session
from quixote.html import TemplateIO
-from .qommon import _, force_str
+from .qommon import _, N_, force_str
from .qommon import misc
from .qommon import get_logger
from .qommon.cron import CronJob
@@ -35,6 +35,7 @@ from .qommon.form import *
from .qommon.humantime import seconds2humanduration
from .qommon.misc import get_variadic_url
from .qommon.publisher import get_publisher_class
+from .qommon.afterjobs import AfterJob
from .qommon.storage import StorableObject
from .qommon.template import Template
from .qommon.xml_storage import XmlStorableObject
@@ -843,6 +844,13 @@ def build_agenda_datasources(publisher):
datasource.remove_self()
+class RefreshAgendas(AfterJob):
+ label = N_('Refreshing agendas')
+
+ def execute(self):
+ build_agenda_datasources(get_publisher())
+
+
if get_publisher_class():
# every hour: check for agenda datasources
get_publisher_class().register_cronjob(
diff --git a/wcs/templates/wcs/backoffice/data-sources.html b/wcs/templates/wcs/backoffice/data-sources.html
index deb75c353..8d32272d6 100644
--- a/wcs/templates/wcs/backoffice/data-sources.html
+++ b/wcs/templates/wcs/backoffice/data-sources.html
@@ -4,6 +4,9 @@
{% block appbar-title %}{% trans "Data Sources" %}{% endblock %}
{% block appbar-actions %}
+{% if has_chrono %}
+{% trans "Refresh agendas" %}
+{% endif %}
{% trans "Import" %}
{% trans "New Data Source" %}
{% endblock %}