-
Notifications
You must be signed in to change notification settings - Fork 7
/
client.py
1677 lines (1416 loc) · 59.6 KB
/
client.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
import cgi
import datetime
import logging
import os
import re
import sys
from six.moves import urllib
import urllib2
import ssl
import uuid
import requests
from xml.dom import minidom
import lxml.etree as etree
import shutil
import logging
# Smartly import hashlib and fall back on md5
try:
from hashlib import md5
except ImportError:
from md5 import md5
class Configuration(object):
"""
Stores the configuration elements required by the API.
"""
def __init__(self, appid, secret,
serviceurl, origin='rusticisoftware.pythonlibrary.2.0.0'):
self.appid = appid
self.secret = secret
self.serviceurl = serviceurl
self.origin = origin;
def __repr__(self):
return 'Configuration for AppID %s from origin %s' % (
self.appid, self.origin)
class ScormCloudService(object):
"""
Primary cloud service object that provides access to the more specific
service areas, like the RegistrationService.
"""
def __init__(self, configuration):
self.config = configuration
self.__handler_cache = {}
@classmethod
def withconfig(cls, config):
"""
Named constructor that creates a ScormCloudService with the specified
Configuration object.
Arguments:
config -- the Configuration object holding the required configuration
values for the SCORM Cloud API
"""
return cls(config)
@classmethod
def withargs(cls, appid, secret, serviceurl, origin):
"""
Named constructor that creates a ScormCloudService with the specified
configuration values.
Arguments:
appid -- the AppID for the application defined in the SCORM Cloud
account
secret -- the secret key for the application
serviceurl -- the service URL for the SCORM Cloud web service. For
example, http://cloud.scorm.com/EngineWebServices
origin -- the origin string for the application software using the
API/Python client library
"""
return cls(Configuration(appid, secret, serviceurl, origin))
def get_course_service(self):
"""
Retrieves the CourseService.
"""
return CourseService(self)
def get_debug_service(self):
"""
Retrieves the DebugService.
"""
return DebugService(self)
def get_dispatch_service(self):
"""
Retrieves the DebugService.
"""
return DispatchService(self)
def get_registration_service(self):
"""
Retrieves the RegistrationService.
"""
return RegistrationService(self)
def get_invitation_service(self):
"""
Retrieves the InvitationService.
"""
return InvitationService(self)
def get_reporting_service(self):
"""
Retrieves the ReportingService.
"""
return ReportingService(self)
def get_upload_service(self):
"""
Retrieves the UploadService.
"""
return UploadService(self)
def request(self):
"""
Convenience method to create a new ServiceRequest.
"""
return ServiceRequest(self)
def make_call(self, method):
"""
Convenience method to create and call a simple ServiceRequest (no
parameters).
"""
return self.request().call_service(method)
def get_lrsaccount_service(self):
return LrsAccountService(self)
def get_application_service(self):
return ApplicationService(self)
def get_post_back_service(self):
return PostbackService(self)
class DebugService(object):
"""
Debugging and testing service that allows you to check the status of the
SCORM Cloud and test your configuration settings.
"""
def __init__(self, service):
self.service = service
def ping(self):
"""
A simple ping that checks the connection to the SCORM Cloud.
"""
try:
xmldoc = self.service.make_call('rustici.debug.ping')
return xmldoc.documentElement.attributes['stat'].value == 'ok'
except Exception:
return False
def authping(self):
"""
An authenticated ping that checks the connection to the SCORM Cloud
and verifies the configured credentials.
"""
try:
xmldoc = self.service.make_call('rustici.debug.authPing')
return xmldoc.documentElement.attributes['stat'].value == 'ok'
except Exception:
return False
class DispatchService(object):
def __init__(self, service):
self.service = service
def get_dispatch_info(self, dispatchid):
request = self.service.request()
request.parameters['dispatchid'] = dispatchid
result = request.call_service('rustici.dispatch.getDispatchInfo')
return result
def get_destination_info(self, destinationid):
request = self.service.request()
request.parameters['destinationid'] = dispatchid
result = request.call_service('rustici.dispatch.getDestinationInfo')
return result
def download_dispatches(self, dispatchid=None, tags=None, destinationid=None, courseid=None):
request = self.service.request()
if dispatchid is not None:
request.parameters['dispatchid'] = dispatchid
if destinationid is not None:
request.parameters['destinationid'] = destinationid
if tags is not None:
request.parameters['tags'] = tags
if courseid is not None:
request.parameters['courseid'] = courseid
url = request.construct_url('rustici.dispatch.downloadDispatches')
r = request.send_post(url, None)
with open("dispatch.zip", "w") as f:
f.write(r)
return "success"
class ApplicationService(object):
"""
Used for testing Nathan's Application web service changes
"""
def __init__(self, service):
self.service = service
def create_application(self, name):
request = self.service.request()
request.parameters['appid'] = self.service.config.appid
request.parameters['name'] = name
try:
result = request.call_service('rustici.application.createApplication')
result = ApplicationCallbackData.list_from_result(result)
except urllib.error.HTTPError:
logging.exception('failed to create application')
return result
def get_app_list(self):
request = self.service.request()
request.parameters['appid'] = self.service.config.appid
result = "failed"
try:
result = request.call_service('rustici.application.getAppList')
result = ApplicationCallbackData.list_from_list(result)
except urllib.error.HTTPError:
logging.exception('failed to get list')
return result
def get_app_info(self, childAppId):
request = self.service.request()
request.parameters['appid'] = self.service.config.appid
request.parameters['childappid'] = childAppId
result = "failed"
try:
result = request.call_service('rustici.application.getAppInfo')
result = ApplicationCallbackData.list_from_result(result)
except urllib.error.HTTPError:
logging.exception('failed to get info')
return result
def update_app(self, childAppId, appName):
request = self.service.request()
request.parameters['appid'] = self.service.config.appid
request.parameters['childappid'] = childAppId
if(appName != ''):
request.parameters['name'] = appName
result = "failed"
try:
result = request.call_service('rustici.application.updateApplication')
result = ApplicationCallbackData.list_from_result(result)
except urllib.error.HTTPError:
logging.exception('failed to update')
return result
class LrsAccountService(object):
"""
Used for testing LRSAccountService stuff
"""
def __init__(self, service):
self.service = service
def get_lrs_callback_url(self):
request = self.service.request()
request.parameters['appid'] = self.service.config.appid
lrs = "Service call failed"
try:
result = request.call_service('rustici.lrsaccount.getAppLrsAuthCallbackUrl')
lrs = LrsCallbackData.list_from_result(result)
except urllib.error.HTTPError:
logging.exception('failed')
return lrs
def get_reset_lrs_callback_url(self):
request = self.service.request()
request.parameters['appid'] = self.service.config.appid
success = False
try:
result = request.call_service('rustici.lrsaccount.resetAppLrsAuthCallbackUrl')
success = LrsCallbackData.get_success(result)
except urllib.error.HTTPError:
logging.exception('failed')
return success
def set_lrs_callback_url(self, lrsUrl):
request = self.service.request()
request.parameters['appid'] = self.service.config.appid
request.parameters['lrsAuthCallbackUrl'] = lrsUrl
success = False
try:
result = request.call_service('rustici.lrsaccount.setAppLrsAuthCallbackUrl');
success = LrsCallbackData.get_success(result)
except urllib.error.HTTPError:
logging.exception('failed')
return success
def edit_activity_provider(self, activityProviderId, appIds, permissionsLevel):
request = self.service.request()
request.parameters['appid'] = self.service.config.appid
request.parameters['accountkey'] = activityProviderId
if appIds != "":
request.parameters['allowedendpoints'] = appIds
if permissionsLevel != "":
request.parameters['permissionslevel'] = permissionsLevel
success = False
try:
result = request.call_service('rustici.lrsaccount.editActivityProvider')
success = ActivityProviderCallbackData.activity_provider_from_result(result)
except urllib.error.HTTPError:
logging.exception('failed')
return success
def list_activity_providers(self):
request = self.service.request()
request.parameters['appid'] = self.service.config.appid
success = False
try:
result = request.call_service('rustici.lrsaccount.listActivityProviders')
success = ActivityProviderCallbackData.activity_providers_from_result(result)
except urllib.error.HTTPError:
logging.exception('failed')
except KeyError:
logging.exception('key error fail')
return success
class UploadService(object):
"""
Service that provides functionality to upload files to the SCORM Cloud.
"""
def __init__(self, service):
self.service = service
def get_upload_token(self):
"""
Retrieves an upload token which must be used to successfully upload a
file.
"""
xmldoc = self.service.make_call('rustici.upload.getUploadToken')
serverNodes = xmldoc.getElementsByTagName('server')
tokenidNodes = xmldoc.getElementsByTagName('id')
server = None
for s in serverNodes:
server = s.childNodes[0].nodeValue
tokenid = None
for t in tokenidNodes:
tokenid = t.childNodes[0].nodeValue
if server and tokenid:
token = UploadToken(server,tokenid)
return token
else:
return None
def get_upload_url(self, callbackurl):
"""
Returns a URL that can be used to upload a file via HTTP POST, through
an HTML form element action, for example.
"""
token = self.get_upload_token()
if token:
request = self.service.request()
request.parameters['tokenid'] = token.tokenid
request.parameters['redirecturl'] = callbackurl
return request.construct_url('rustici.upload.uploadFile')
else:
return None
def delete_file(self, location):
"""
Deletes the specified file.
"""
locParts = location.split("/")
request = self.service.request()
request.parameters['file'] = locParts[len(locParts) - 1]
return request.call_service('rustici.upload.deleteFiles')
def get_upload_progress(self, token):
request = self.service.request()
request.parameters['token'] = token
return request.call_service('rustici.upload.getUploadProgress')
class CourseService(object):
"""
Service that provides methods to manage and interact with courses on the
SCORM Cloud. These methods correspond to the "rustici.course.*" web service
methods.
"""
def __init__(self, service):
self.service = service
def exists(self, courseid):
request = self.service.request()
request.parameters['courseid'] = courseid
result = request.call_service('rustici.course.exists')
return result
def import_course(self, courseid, file_handle):
request = self.service.request()
request.parameters['courseid'] = courseid
files = { 'file': file_handle }
url = request.construct_url('rustici.course.importCourse')
res = requests.post(url, files=files)
xmldoc = request.get_xml(res.content)
return ImportResult.list_from_result(xmldoc)
def import_course_async(self, courseid, file_handle):
request = self.service.request()
request.parameters['courseid'] = courseid
files = { 'file': file_handle }
url = request.construct_url('rustici.course.importCourseAsync')
res = requests.post(url, files=files)
xmldoc = request.get_xml(res.content)
return xmldoc.getElementsByTagName('id')[0].childNodes[0].nodeValue
def get_async_import_result(self, token):
request = self.service.request()
request.parameters['token'] = token
url = request.construct_url('rustici.course.getAsyncImportResult')
res = requests.post(url)
xmldoc = request.get_xml(res.content)
return AsyncImportResult.result_from_xmldoc(xmldoc)
def import_uploaded_course(self, courseid, path):
"""
Imports a SCORM PIF (zip file) from an existing zip file on the SCORM
Cloud server.
Arguments:
courseid -- the unique identifier for the course
path -- the relative path to the zip file to import
"""
request = self.service.request()
request.parameters['courseid'] = courseid
request.parameters['path'] = path
result = request.call_service('rustici.course.importCourse')
ir = ImportResult.list_from_result(result)
return ir
def delete_course(self, courseid):
"""
Deletes the specified course.
Arguments:
courseid -- the unique identifier for the course
"""
request = self.service.request()
request.parameters['courseid'] = courseid
return request.call_service('rustici.course.deleteCourse')
def get_assets(self, courseid, pathToSave, path=None):
"""
Downloads a file from a course by path. If no path is provided, all the
course files will be downloaded contained in a zip file.
Arguments:
courseid -- the unique identifier for the course
pathToSave -- the path where the downloaded content should be saved.
If not provided or is None, the file will be saved at the location of this file.
path -- the path (relative to the course root) of the file to download.
If not provided or is None, all course files will be downloaded.
"""
request = self.service.request()
request.parameters['courseid'] = courseid
if (path is not None):
request.parameters['path'] = path
request.download_file('rustici.course.getAssets', pathToSave)
def get_course_list(self, courseIdFilterRegex=None):
"""
Retrieves a list of CourseData elements for all courses owned by the
configured AppID that meet the specified filter criteria.
Arguments:
courseIdFilterRegex -- (optional) Regular expression to filter courses
by ID
"""
request = self.service.request()
if courseIdFilterRegex is not None:
request.parameters['filter'] = courseIdFilterRegex
result = request.call_service('rustici.course.getCourseList')
courses = CourseData.list_from_result(result)
return courses
def get_preview_url(self, courseid, redirecturl, versionid=None, stylesheeturl=None):
"""
Gets the URL that can be opened to preview the course without the need
for a registration.
Arguments:
courseid -- the unique identifier for the course
redirecturl -- the URL to which the browser should redirect upon course
exit
stylesheeturl -- the URL for the CSS stylesheet to include
"""
request = self.service.request()
request.parameters['courseid'] = courseid
request.parameters['redirecturl'] = redirecturl
if stylesheeturl is not None:
request.parameters['stylesheet'] = stylesheeturl
if versionid is not None:
request.parameters['versionid'] = str(versionid)
url = request.construct_url('rustici.course.preview')
logging.info('preview link: '+ url)
return url
def get_metadata(self, courseid):
"""
Gets the course metadata in XML format.
Arguments:
courseid -- the unique identifier for the course
"""
request = self.service.request()
request.parameters['courseid'] = courseid
return request.call_service('rustici.course.getMetadata')
def get_property_editor_url(self, courseid, stylesheetUrl=None,
notificationFrameUrl=None):
"""
Gets the URL to view/edit the package properties for the course.
Typically used within an IFRAME element.
Arguments:
courseid -- the unique identifier for the course
stylesheeturl -- URL to a custom editor stylesheet
notificationFrameUrl -- Tells the property editor to render a sub-iframe
with this URL as the source. This can be used to simulate an
"onload" by using a notificationFrameUrl that is on the same domain
as the host system and calling parent.parent.method()
"""
request = self.service.request()
request.parameters['courseid'] = courseid
if stylesheetUrl is not None:
request.parameters['stylesheet'] = stylesheetUrl
if notificationFrameUrl is not None:
request.parameters['notificationframesrc'] = notificationFrameUrl
url = request.construct_url('rustici.course.properties')
logging.info('properties link: '+url)
return url
def get_attributes(self, courseid):
"""
Retrieves the list of associated attributes for the course.
Arguments:
courseid -- the unique identifier for the course
versionid -- the specific version of the course
"""
request = self.service.request()
request.parameters['courseid'] = courseid
xmldoc = request.call_service('rustici.course.getAttributes')
attrNodes = xmldoc.getElementsByTagName('attribute')
atts = {}
for an in attrNodes:
atts[an.attributes['name'].value] = an.attributes['value'].value
return atts
def update_attributes(self, courseid, attributePairs):
"""
Updates the specified attributes for the course.
Arguments:
courseid -- the unique identifier for the course
attributePairs -- the attribute name/value pairs to update
"""
request = self.service.request()
request.parameters['courseid'] = courseid
for (key, value) in attributePairs.items():
request.parameters[key] = value
xmldoc = request.call_service('rustici.course.updateAttributes')
attrNodes = xmldoc.getElementsByTagName('attribute')
atts = {}
for an in attrNodes:
atts[an.attributes['name'].value] = an.attributes['value'].value
return atts
class PostbackService(object):
def __init__(self, service):
self.service = service
def get_postback_info(self, appid, regid):
request = self.service.request()
request.parameters['appid'] = appid
request.parameters['regid'] = regid
xmldoc = request.call_service('rustici.registration.getPostbackInfo')
pbd = PostbackData(xmldoc)
logging.debug('postback registration id: %s', pbd.registrationId)
return pbd
class RegistrationService(object):
"""
Service that provides methods for managing and interacting with
registrations on the SCORM Cloud. These methods correspond to the
"rustici.registration.*" web service methods.
"""
def __init__(self, service):
self.service = service
def test_registration_post(self,authtype, postbackurl,urlname, passw):
request = self.service.request()
request.parameters['authtype'] = authtype
request.parameters['postbackurl'] = postbackurl
request.parameters['urlname'] = urlname
request.parameters['urlpass'] = passw
return request.call_service('rustici.registration.testRegistrationPostUrl')
def update_postback_info(self, regid, url, authtype='', user='', password='', resultsformat='course'):
request = self.service.request()
request.parameters['regid'] = regid
request.parameters['url'] = url
request.parameters['authtype'] = authtype
request.parameters['name'] = user
request.parameters['password'] = password
request.parameters['resultsformat'] = resultsformat
return request.call_service('rustici.registration.updatePostbackInfo')
def create_registration(self, regid, courseid, userid, fname, lname, postbackUrl=None,
email=None, learnerTags=None, courseTags=None, registrationTags=None):
"""
Creates a new registration (an instance of a user taking a course).
Arguments:
regid -- the unique identifier for the registration
courseid -- the unique identifier for the course
userid -- the unique identifier for the learner
fname -- the learner's first name
lname -- the learner's last name
email -- the learner's email address
"""
if regid is None:
regid = str(uuid.uuid1())
request = self.service.request()
request.parameters['appid'] = self.service.config.appid
request.parameters['courseid'] = courseid
request.parameters['regid'] = regid
if fname is not None:
request.parameters['fname'] = fname
if lname is not None:
request.parameters['lname'] = lname
request.parameters['learnerid'] = userid
if email is not None:
request.parameters['email'] = email
if learnerTags is not None:
request.parameters['learnerTags'] = learnerTags
if courseTags is not None:
request.parameters['courseTags'] = courseTags
if registrationTags is not None:
request.parameters['registrationTags'] = registrationTags
if postbackUrl is not None:
request.parameters['postbackurl'] = postbackUrl
xmldoc = request.call_service('rustici.registration.createRegistration')
successNodes = xmldoc.getElementsByTagName('success')
if successNodes.length == 0:
raise ScormCloudError("Create Registration failed. " +
xmldoc.err.attributes['msg'])
return regid
def get_launch_url(self, regid, redirecturl, cssUrl=None, courseTags=None,
learnerTags=None, registrationTags=None):
"""
Gets the URL to directly launch the course in a web browser.
Arguments:
regid -- the unique identifier for the registration
redirecturl -- the URL to which the SCORM player will redirect upon
course exit
cssUrl -- the URL to a custom stylesheet
courseTags -- comma-delimited list of tags to associate with the
launched course
learnerTags -- comma-delimited list of tags to associate with the
learner launching the course
registrationTags -- comma-delimited list of tags to associate with the
launched registration
"""
request = self.service.request()
request.parameters['regid'] = regid
request.parameters['redirecturl'] = redirecturl + '?regid=' + regid
if cssUrl is not None:
request.parameters['cssurl'] = cssUrl
if courseTags is not None:
request.parameters['coursetags'] = courseTags
if learnerTags is not None:
request.parameters['learnertags'] = learnerTags
if registrationTags is not None:
request.parameters['registrationTags'] = registrationTags
url = request.construct_url('rustici.registration.launch')
return url
def get_registration_list(self, regIdFilterRegex=None,
courseIdFilterRegex=None):
"""
Retrieves a list of registration associated with the configured AppID.
Can optionally be filtered by registration or course ID.
Arguments:
regIdFilterRegex -- (optional) the regular expression used to filter the
list by registration ID
courseIdFilterRegex -- (optional) the regular expression used to filter
the list by course ID
"""
request = self.service.request()
if regIdFilterRegex is not None:
request.parameters['filter'] = regIdFilterRegex
if courseIdFilterRegex is not None:
request.parameters['coursefilter'] = courseIdFilterRegex
result = request.call_service(
'rustici.registration.getRegistrationList')
regs = RegistrationData.list_from_result(result)
return regs
def get_registration_result(self, regid, resultsformat):
"""
Gets information about the specified registration.
Arguments:
regid -- the unique identifier for the registration
resultsformat -- (optional) can be "course", "activity", or "full" to
determine the level of detail returned. The default is "course"
"""
request = self.service.request()
request.parameters['regid'] = regid
request.parameters['resultsformat'] = resultsformat
return request.call_service(
'rustici.registration.getRegistrationResult')
def get_registration_detail(self, regid):
"""
This method will return some detail for the registration specified with
the given appid and registrationid, including information regarding
registration instances.
Arguments:
regid -- the unique identifier for the registration
"""
request = self.service.request()
request.parameters['regid'] = regid
return request.call_service(
'rustici.registration.getRegistrationDetail')
def get_launch_history(self, regid):
"""
Retrieves a list of LaunchInfo objects describing each launch. These
LaunchInfo objects do not contain the full launch history log; use
get_launch_info to retrieve the full launch information.
Arguments:
regid -- the unique identifier for the registration
"""
request = self.service.request()
request.parameters['regid'] = regid
return request.call_service('rustici.registration.getLaunchHistory')
def get_launch_info(self, launchid):
request = self.service.request()
request.parameters['launchid'] = launchid
return request.call_service('rustici.registration.getLaunchInfo')
def reset_registration(self, regid):
"""
Resets all status data for the specified registration, essentially
restarting the course for the associated learner.
Arguments:
regid -- the unique identifier for the registration
"""
request = self.service.request()
request.parameters['regid'] = regid
return request.call_service('rustici.registration.resetRegistration')
def exists(self, regid):
"""
Checks if a registration exists
Arguments:
regid -- the unique identifier for the registration
"""
request = self.service.request()
request.parameters['regid'] = regid
return request.call_service('rustici.registration.exists')
def reset_global_objectives(self, regid):
"""
Clears global objective data for the specified registration.
Arguments:
regid -- the unique identifier for the registration
"""
request = self.service.request()
request.parameters['regid'] = regid
return request.call_service(
'rustici.registration.resetGlobalObjectives')
def delete_registration(self, regid):
"""
Deletes the specified registration.
Arguments:
regid -- the unique identifier for the registration
"""
request = self.service.request()
request.parameters['regid'] = regid
return request.call_service('rustici.registration.deleteRegistration')
class InvitationService(object):
def __init__(self, service):
self.service = service
def create_invitation(self,courseid,tags=None,publicInvitation='true',send='true',addresses=None,emailSubject=None,emailBody=None,creatingUserEmail=None,
registrationCap=None,postbackUrl=None,authType=None,urlName=None,urlPass=None,resultsFormat=None,async=False):
request = self.service.request()
request.parameters['courseid'] = courseid
request.parameters['send'] = send
request.parameters['public'] = publicInvitation
if addresses is not None:
request.parameters['addresses'] = addresses
if emailSubject is not None:
request.parameters['emailSubject'] = emailSubject
if emailBody is not None:
request.parameters['emailBody'] = emailBody
if creatingUserEmail is not None:
request.parameters['creatingUserEmail'] = creatingUserEmail
if registrationCap is not None:
request.parameters['registrationCap'] = registrationCap
if postbackUrl is not None:
request.parameters['postbackUrl'] = postbackUrl
if authType is not None:
request.parameters['authType'] = authType
if urlName is not None:
request.parameters['urlName'] = urlName
if urlPass is not None:
request.parameters['urlPass'] = urlPass
if resultsFormat is not None:
request.parameters['resultsFormat'] = resultsFormat
if tags is not None:
request.parameters['tags'] = tags
if async:
data = request.call_service('rustici.invitation.createInvitationAsync')
else:
data = request.call_service('rustici.invitation.createInvitation')
return data
def get_invitation_list(self, filter=None,coursefilter=None):
request = self.service.request()
if filter is not None:
request.parameters['filter'] = filter
if coursefilter is not None:
request.parameters['coursefilter'] = coursefilter
data = request.call_service('rustici.invitation.getInvitationList')
return data
def get_invitation_status(self, invitationId):
request = self.service.request()
request.parameters['invitationId'] = invitationId
data = request.call_service('rustici.invitation.getInvitationStatus')
return data
def get_invitation_info(self, invitationId,detail=None):
request = self.service.request()
request.parameters['invitationId'] = invitationId
if detail is not None:
request.parameters['detail'] = detail
data = request.call_service('rustici.invitation.getInvitationInfo')
return data
def change_status(self, invitationId,enable,open=None):
request = self.service.request()
request.parameters['invitationId'] = invitationId
request.parameters['enable'] = enable
if open is not None:
request.parameters['open'] = open
data = request.call_service('rustici.invitation.changeStatus')
return data
class ReportingService(object):
"""
Service that provides methods for interacting with the Reportage service.
"""
def __init__(self, service):
self.service = service
def get_reportage_date(self):
"""
Gets the date/time, according to Reportage.
"""
reportUrl = (self._get_reportage_service_url() +
'Reportage/scormreports/api/getReportDate.php?appId=' +
self.service.config.appid)
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
cloudsocket = urllib.request.urlopen(reportUrl, None, 2000, context=ctx)
reply = cloudsocket.read()
cloudsocket.close()
d = datetime.datetime
return d.strptime(reply,"%Y-%m-%d %H:%M:%S")
def get_reportage_auth(self, navperm, allowadmin):
"""
Authenticates against the Reportage application, returning a session
string used to make subsequent calls to launchReport.
Arguments:
navperm -- the Reportage navigation permissions to assign to the
session. If "NONAV", the session will be prevented from navigating
away from the original report/widget. "DOWNONLY" allows the user to
drill down into additional detail. "FREENAV" allows the user full
navigation privileges and the ability to change any reporting
parameter.
allowadmin -- if True, the Reportage session will have admin privileges
"""
request = self.service.request()
request.parameters['navpermission'] = navperm
request.parameters['admin'] = 'true' if allowadmin else 'false'
xmldoc = request.call_service('rustici.reporting.getReportageAuth')
token = xmldoc.getElementsByTagName('auth')
if token.length > 0:
return token[0].childNodes[0].nodeValue
else:
return None
def _get_reportage_service_url(self):
"""
Returns the base Reportage URL.
"""
return self.service.config.serviceurl.replace('EngineWebServices','')
def _get_base_reportage_url(self):
return (self._get_reportage_service_url() + 'Reportage/reportage.php' +
'?appId=' + self.service.config.appid)
def get_report_url(self, auth, reportUrl):
"""
Returns an authenticated URL that can launch a Reportage session at
the specified Reportage entry point.
Arguments:
auth -- the Reportage authentication string, as retrieved from
get_reportage_auth
reportUrl -- the URL to the desired Reportage entry point
"""
request = self.service.request()
request.parameters['auth'] = auth
request.parameters['reporturl'] = reportUrl
url = request.construct_url('rustici.reporting.launchReport')
return url
def get_reportage_url(self, auth):
"""