cybertools.scorm package basically operating
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1713 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
76ae5d8bbf
commit
b65f9d1a6d
2 changed files with 59 additions and 4 deletions
|
@ -10,7 +10,7 @@ In order to work with the SCORM API we first need a tracking storage.
|
||||||
>>> tracks = TrackingStorage()
|
>>> tracks = TrackingStorage()
|
||||||
|
|
||||||
We can now create a ScormAPI adapter. Note that this adapter is stateless
|
We can now create a ScormAPI adapter. Note that this adapter is stateless
|
||||||
as it is usually created anew upon each request.
|
as usually a new instance is created upon each request.
|
||||||
|
|
||||||
>>> from cybertools.scorm.base import ScormAPI
|
>>> from cybertools.scorm.base import ScormAPI
|
||||||
>>> api = ScormAPI(tracks, 'a001', 0, 'user1')
|
>>> api = ScormAPI(tracks, 'a001', 0, 'user1')
|
||||||
|
@ -31,7 +31,7 @@ Then we can set some values.
|
||||||
|
|
||||||
Depending on the data elements the values entered are kept together in
|
Depending on the data elements the values entered are kept together in
|
||||||
one track or stored in separate track objects. So there is a separate
|
one track or stored in separate track objects. So there is a separate
|
||||||
track for each interaction and one track for all the other elements.
|
track for each interaction and one additional track for all the other elements.
|
||||||
|
|
||||||
>>> for t in sorted(tracks.values(), key=lambda x: x.timeStamp):
|
>>> for t in sorted(tracks.values(), key=lambda x: x.timeStamp):
|
||||||
... print t.data
|
... print t.data
|
||||||
|
@ -48,3 +48,17 @@ to care about the storage in different track objects.
|
||||||
('q007', '0')
|
('q007', '0')
|
||||||
>>> api.getValue('cmi.interactions.1.result')
|
>>> api.getValue('cmi.interactions.1.result')
|
||||||
('incorrect', '0')
|
('incorrect', '0')
|
||||||
|
|
||||||
|
We can also query special elements like _count and _children.
|
||||||
|
|
||||||
|
>>> api.getValue('cmi.objectives._count')
|
||||||
|
(0, '0')
|
||||||
|
>>> api.getValue('cmi.interactions._count')
|
||||||
|
(2, '0')
|
||||||
|
|
||||||
|
>>> api.getValue('cmi.interactions._children')
|
||||||
|
(('id', 'type', 'objectives', 'timestamp', 'correct_responses',
|
||||||
|
'weighting', 'learner_response', 'result', 'latency', 'description'), '0')
|
||||||
|
>>> api.getValue('cmi.objectives.5.score._children')
|
||||||
|
(('scaled', 'raw', 'min', 'max'), '0')
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,19 @@ from cybertools.tracking.btree import TrackingStorage
|
||||||
|
|
||||||
OK = '0'
|
OK = '0'
|
||||||
|
|
||||||
|
_children = {
|
||||||
|
'cmi.comments_from_learner': ('comment', 'location', 'timestamp'),
|
||||||
|
'cmi.comments_from_lms': ('comment', 'location', 'timestamp'),
|
||||||
|
'cmi.interactions': ('id', 'type', 'objectives', 'timestamp',
|
||||||
|
'correct_responses', 'weighting', 'learner_response',
|
||||||
|
'result', 'latency', 'description'),
|
||||||
|
'cmi.learner_preference': ('audio_level', 'language',
|
||||||
|
'delivery_speed', 'audio_captioning'),
|
||||||
|
'cmi.objectives': ('id', 'score', 'success_status', 'completion_status',
|
||||||
|
'description'),
|
||||||
|
'score': ('scaled', 'raw', 'min', 'max'),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class ScormAPI(object):
|
class ScormAPI(object):
|
||||||
""" ScormAPI objects are temporary adapters created by
|
""" ScormAPI objects are temporary adapters created by
|
||||||
|
@ -81,8 +94,18 @@ class ScormAPI(object):
|
||||||
|
|
||||||
def getValue(self, element):
|
def getValue(self, element):
|
||||||
tracks = self.storage.getUserTracks(self.taskId, self.runId, self.userId)
|
tracks = self.storage.getUserTracks(self.taskId, self.runId, self.userId)
|
||||||
|
if element.endswith('._count'):
|
||||||
|
base = element[:-len('._count')]
|
||||||
|
if element.startswith('cmi.interactions.'):
|
||||||
|
return self._countSubtracks(tracks, base), OK
|
||||||
|
else:
|
||||||
|
data = self._getTrackData(tracks, '')
|
||||||
|
return self._countSubelements(data, base), OK
|
||||||
|
if element.endswith('_children'):
|
||||||
|
base = element[:-len('._children')]
|
||||||
|
return self._getChildren(base)
|
||||||
prefix, key = self._splitKey(element)
|
prefix, key = self._splitKey(element)
|
||||||
data = self._getTrackData(tracks, prefix) or {}
|
data = self._getTrackData(tracks, prefix)
|
||||||
if key in data:
|
if key in data:
|
||||||
return data[key], OK
|
return data[key], OK
|
||||||
else:
|
else:
|
||||||
|
@ -103,8 +126,26 @@ class ScormAPI(object):
|
||||||
return '', element
|
return '', element
|
||||||
|
|
||||||
def _getTrackData(self, tracks, prefix):
|
def _getTrackData(self, tracks, prefix):
|
||||||
track = None
|
|
||||||
for tr in reversed(sorted(tracks, key=lambda x: x.timeStamp)):
|
for tr in reversed(sorted(tracks, key=lambda x: x.timeStamp)):
|
||||||
if tr and tr.data.get('key_prefix', None) == prefix:
|
if tr and tr.data.get('key_prefix', None) == prefix:
|
||||||
return tr.data
|
return tr.data
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
def _countSubelements(self, data, element):
|
||||||
|
result = set()
|
||||||
|
for key in data:
|
||||||
|
if key.startswith(element) and key not in result:
|
||||||
|
result.add(key)
|
||||||
|
return len(result)
|
||||||
|
|
||||||
|
def _countSubtracks(self, tracks, base):
|
||||||
|
return len([tr for tr in tracks if tr.data.get('key_prefix').startswith(base)])
|
||||||
|
|
||||||
|
def _getChildren(self, base):
|
||||||
|
if base.endswith('.score'):
|
||||||
|
base = 'score'
|
||||||
|
if base in _children:
|
||||||
|
return _children[base], OK
|
||||||
|
else:
|
||||||
|
return '', '401'
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue