lingo/lingo/agendas/chrono.py

135 lines
4.1 KiB
Python

# lingo - payment and billing system
# Copyright (C) 2022 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/>.
import json
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from requests.exceptions import RequestException
from lingo.agendas.models import Agenda
from lingo.utils import requests
class ChronoError(Exception):
pass
def is_chrono_enabled():
return hasattr(settings, 'KNOWN_SERVICES') and settings.KNOWN_SERVICES.get('chrono')
def get_chrono_service():
if not is_chrono_enabled():
return {}
return list(settings.KNOWN_SERVICES.get('chrono').values())[0]
def get_chrono_json(path, log_errors=True):
chrono_site = get_chrono_service()
if chrono_site is None:
return
try:
response = requests.get(
path,
remote_service=chrono_site,
without_user=True,
headers={'accept': 'application/json'},
log_errors=log_errors,
)
response.raise_for_status()
except RequestException as e:
if e.response is not None:
try:
# return json if available (on 404 responses by example)
return e.response.json()
except json.JSONDecodeError:
pass
return
return response.json()
def collect_agenda_data():
result = get_chrono_json('api/agenda/')
if result is None:
return
if result.get('data') is None:
return
agenda_data = []
for agenda in result['data']:
if agenda['kind'] != 'events':
continue
agenda_data.append(
{
'slug': agenda['slug'],
'label': agenda['text'],
'category_slug': agenda['category'],
'category_label': agenda['category_label'],
}
)
return agenda_data
def refresh_agendas():
result = collect_agenda_data()
if result is None:
return
# fetch existing agendas
existing_agendas = {a.slug: a for a in Agenda.objects.all()}
seen_agendas = []
# build agendas from chrono
for agenda_data in result:
slug = agenda_data['slug']
agenda = existing_agendas.get(slug) or Agenda(slug=slug)
for key, value in agenda_data.items():
if key == 'slug':
continue
setattr(agenda, key, value)
agenda.save()
seen_agendas.append(agenda.slug)
# now check outdated agendas
for slug, agenda in existing_agendas.items():
if slug not in seen_agendas:
agenda.delete()
def get_event(event_slug):
result = get_chrono_json('api/agendas/events/?slots=%s' % event_slug)
if not result:
raise ChronoError(_('Unable to get event details'))
if result.get('err'):
raise ChronoError(_('Unable to get event details (%s)') % result['err_desc'])
if not result.get('data'):
raise ChronoError(_('Unable to get event details'))
return result['data'][0]
def get_subscriptions(agenda_slug, user_external_id):
result = get_chrono_json(
'api/agenda/%s/subscription/?user_external_id=%s' % (agenda_slug, user_external_id)
)
if not result or not result.get('data'):
raise ChronoError(_('Unable to get subscription details'))
if result.get('err'):
raise ChronoError(_('Unable to get subscription details (%s)') % result['err_desc'])
if not result.get('data'):
raise ChronoError(_('Unable to get subscription details'))
return result['data']