Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Kolibri 0.16 tasks API #140

Merged
merged 7 commits into from
Dec 11, 2023
87 changes: 87 additions & 0 deletions lib/eibkolibri.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

import eib
import enum
import logging
from netrc import netrc
import os
Expand All @@ -29,6 +30,12 @@

class RemoteKolibri:
"""Kolibri remote instance"""

class Series(enum.Enum):
"""Supported Kolibri server series"""
KOLIBRI_0_15 = enum.auto()
KOLIBRI_0_16 = enum.auto()
Comment on lines +36 to +37
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A chaotic alternative would be:

        KOLIBRI_0_15 = 0.15
        KOLIBRI_0_16 = 0.16

I thought this would be rejected but actually it's completely legal and the Python documentation gives an example where enum values are tuples of floats.

https://docs.python.org/3/howto/enum.html#planet


def __init__(self, base_url, username, password):
self.base_url = base_url

Expand All @@ -39,8 +46,19 @@ def __init__(self, base_url, username, password):
'Content-Type': 'application/json',
})

self.series = self._get_server_series()

def import_channel(self, channel_id):
"""Import channel and content on remote Kolibri server"""
if self.series == self.Series.KOLIBRI_0_15:
return self._import_channel_0_15(channel_id)
elif self.series == self.Series.KOLIBRI_0_16:
return self._import_channel_0_16(channel_id)

raise AssertionError('Unsupported server series')

def _import_channel_0_15(self, channel_id):
"""Import channel and content on remote Kolibri 0.15 server"""
# Import channel metadata.
url = urljoin(
self.base_url,
Expand Down Expand Up @@ -78,8 +96,39 @@ def import_channel(self, channel_id):
job = resp.json()
self._wait_for_job(job['id'])

def _import_channel_0_16(self, channel_id, update=False):
"""Import channel and content on remote Kolibri 0.16 server"""
url = urljoin(self.base_url, 'api/tasks/tasks/')
data = {
'type': 'kolibri.core.content.tasks.remoteimport',
'channel_id': channel_id,
'channel_name': 'unknown',
'update': update,
# Fetch all nodes so that the channel is fully mirrored.
'renderable_only': False,
'fail_on_error': True,
}
logger.info(f'Importing channel {channel_id}')
with self.session.post(url, json=data) as resp:
try:
resp.raise_for_status()
except requests.exceptions.HTTPError:
logger.error('Failed to import channel: %s', resp.json())
raise
job = resp.json()
self._wait_for_job(job['id'])

def update_channel(self, channel_id):
"""Update channel and content on remote Kolibri server"""
if self.series == self.Series.KOLIBRI_0_15:
return self._update_channel_0_15(channel_id)
elif self.series == self.Series.KOLIBRI_0_16:
return self._update_channel_0_16(channel_id)

raise AssertionError('Unsupported server series')

def _update_channel_0_15(self, channel_id):
"""Update channel and content on remote Kolibri 0.15 server"""
# Generate channel diff stats.
url = urljoin(self.base_url, 'api/tasks/tasks/channeldiffstats/')
data = {'channel_id': channel_id, 'method': 'network'}
Expand Down Expand Up @@ -115,6 +164,28 @@ def update_channel(self, channel_id):
job = resp.json()
self._wait_for_job(job['id'])

def _update_channel_0_16(self, channel_id):
"""Update channel and content on remote Kolibri 0.15 server"""
# Generate channel diff stats.
url = urljoin(self.base_url, 'api/tasks/tasks/')
data = {
'type': 'kolibri.core.content.tasks.remotechanneldiffstats',
'channel_id': channel_id,
'channel_name': 'unknown',
}
logger.info(f'Generating channel {channel_id} diff')
with self.session.post(url, json=data) as resp:
try:
resp.raise_for_status()
except requests.exceptions.HTTPError:
logger.error('Failed to generate channel diff: %s', resp.json())
raise
job = resp.json()
self._wait_for_job(job['id'])

# Update channel metadata and content.
self._import_channel_0_16(channel_id, update=True)

def seed_channel(self, channel_id):
"""Import or update channel and content on remote Kolibri server

Expand All @@ -126,6 +197,22 @@ def seed_channel(self, channel_id):
else:
self.import_channel(channel_id)

def _get_server_series(self):
"""Determine the server Kolibri series"""
url = urljoin(self.base_url, 'api/public/info/')
with self.session.get(url) as resp:
resp.raise_for_status()
info = resp.json()

kolibri_version = info.get('kolibri_version', '')
logger.debug(f'Server Kolibri version: "{kolibri_version}"')
if kolibri_version.startswith('0.15.'):
return self.Series.KOLIBRI_0_15
elif kolibri_version.startswith('0.16.'):
return self.Series.KOLIBRI_0_16

raise Exception(f'Unsupported remote Kolibri version "{kolibri_version}"')

def _get_job_status(self, job_id):
"""Get remote Kolibri job status"""
url = urljoin(self.base_url, f'api/tasks/tasks/{job_id}/')
Expand Down