hackertours-schedule/voc/c3data.py
2025-11-18 19:05:41 +01:00

242 lines
7.1 KiB
Python

import argparse
from os import getenv, path
import json
from gql import Client, gql
from gql.transport.aiohttp import AIOHTTPTransport
from gql.transport.exceptions import TransportQueryError
try:
from .schedule import Schedule
from .event import Event
from .room import Room
from .tools import load_json, write
from . import logger
except ImportError:
import sys
sys.path.append('.')
from schedule import Schedule, Event
from room import Room
from tools import load_json, write
from voc import logger
transport = AIOHTTPTransport(
url=getenv('C3D_URL', 'https://data.c3voc.de/graphql'),
headers={'Authorization': getenv('C3D_TOKEN', 'Basic|Bearer XXXX')}
)
# transport = AIOHTTPTransport(url="http://localhost:5001/graphql")
# Create a GraphQL client using the defined transport
client = Client(transport=transport, fetch_schema_from_transport=True)
def create_conference(schedule: Schedule):
conference = schedule.conference()
data = {
'conference': {
'acronym': conference['acronym'],
'title': conference['title'],
'startDate': conference['start'],
'endDate': conference['end'],
'daysUsingId': {
'create': [{
'index': day['index'],
'startDate': day['day_start'],
'endDate': day['day_end']
} for day in schedule.days()]
},
'roomsUsingId': {
'create': [room.graphql() for room in schedule.rooms(mode='obj')]
}
}
}
# print(json.dumps(data, indent=2))
try:
result = client.execute(gql('''
mutation createConferenceAndDaysAndRooms($input: CreateConferenceInput!) {
createConference(input: $input) {
conference {
id
rooms {
nodes {
guid
slug
name
}
}
}
}
}
'''), variable_values={'input': data})
return result['createConference']
except TransportQueryError as e:
# raise exception, error is not 'conference already exists'
if 'duplicate key value violates unique constraint "conferences_acronym_key"' != e.errors[0]['message']:
raise e
# conference already exists, so try to get required infos
result = get_conference(conference['acronym'])
return result
def get_conference(acronym):
return client.execute(gql('''
query getConferenceAndRooms($acronym: String!) {
conference: conferenceByAcronym(acronym: $acronym) {
id
rooms {
nodes {
guid
name
}
}
}
}'''), variable_values={'acronym': acronym})
def add_room(conference_id, room: Room):
result = client.execute(gql('''
mutation addRoom($input: UpsertRoomInput!) {
upsertRoom(input: $input) {
room { guid, name, slug, meta }
}
}'''), {'input': {'room': {
**room.graphql(),
'conferenceId': conference_id
}
}})
print(result)
return result['upsertRoom']['room']['guid']
def add_event(conference_id, room_id, event: Event):
data = {
"event": {
**(event.graphql()),
"conferenceId": conference_id,
"roomId": room_id,
"eventPeopleUsingGuid": {
"create": [
# TODO: add person guid
{"personId": str(p['id']), "publicName": p.get('name') or p.get('public_name')} for p in event['persons']
]}
}
}
query = gql('''
mutation upsertEvent($input: UpsertEventInput!) {
upsertEvent(input: $input) {
clientMutationId
}
}
''')
try:
write('.')
client.execute(query, {'input': data})
except Exception as e:
print(json.dumps(data, indent=2))
print()
print(e)
print()
def remove_event(event_guid):
try:
client.execute(gql('''
mutation deleteEvent($guid: UUID!) {
deleteEvent(input: {guid: $guid}) { deletedEventNodeId }
}
'''), {'guid': event_guid})
except Exception as e:
print(e)
print()
class C3data:
conference_id = None
room_ids = {}
def __init__(self, schedule: Schedule, create=False):
result = create_conference(schedule) if create else get_conference(schedule.conference('acronym'))
if "errors" in result:
logger.error(result['errors'])
if not result['conference']:
raise "Please create conference in target system using --create"
self.conference_id = result['conference']['id']
self.room_ids = {x['name']: x['guid'] for x in result['conference']['rooms']['nodes']}
# check for new/updated rooms
for room in schedule.rooms(mode='obj'):
if room.name not in self.room_ids:
room_id = add_room(self.conference_id, room)
self.room_ids[room.name] = room_id
# TODO check for new rooms and create them now
def upsert_event(self, event: Event):
if event['room'] in self.room_ids:
room_id = self.room_ids[event['room']]
else:
print('WARNING: Room {} does not exist, creating.'.format(event['room']))
room_id = add_room(self.conference_id, Room(name=event['room'], guid=event.get('room_id')))
self.room_ids[event['room']] = room_id
add_event(self.conference_id, room_id, event)
def depublish_event(self, event_guid):
remove_event(event_guid)
def process_changed_events(self, repo: 'Repo', options):
changed_items = repo.index.diff('HEAD~1', 'events')
for i in changed_items:
write(i.change_type + ': ')
try:
if i.change_type == 'D':
event_guid = path.splitext(path.basename(i.a_path))[0]
self.depublish_event(event_guid)
else:
event = Event(load_json(i.a_path))
self.upsert_event(event)
except KeyboardInterrupt:
break
except Exception as e:
print(e)
if options.exit_when_exception_occours:
raise e
def upsert_schedule(schedule: Schedule, create=False):
c3data = C3data(schedule, create)
try:
schedule.foreach_event(c3data.upsert_event)
except KeyboardInterrupt:
pass
def test():
# schedule = Schedule.from_url('https://fahrplan.events.ccc.de/camp/2019/Fahrplan/schedule.json')
schedule = Schedule.from_file('38C3/everything.schedule.json')
upsert_schedule(schedule, create=True)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('url', action="store", help="url or local path source schedule.json")
parser.add_argument('--create', action="store_true", default=False)
args = parser.parse_args()
schedule = Schedule.from_url(args.url) if args.url.startswith('http') else Schedule.from_file(args.url)
upsert_schedule(schedule, create=args.create)
print('')
print('done')