source: trunk/skins/lemill/OAI-script.py @ 3052

Revision 3052, 25.4 KB checked in by jukka, 9 years ago (diff)

Removed some of the unused templates, community and portfolio related pages are still there. All kinds of work done towards LeMill 3.

Line 
1from Products.CMFCore.utils import getToolByName
2from Products.PythonScripts.standard import html_quote
3
4# this script tries to follow the OAI-protocol (http://www.openarchives.org/OAI/openarchivesprotocol.html)
5# oai_lom should be updated to v4.5...
6# http://lre.eun.org/sites/default/files/docs/LREMAPv4p5w.pdf
7
8context = context.content #So it can work as http://lemill.net/OAI-scipt
9repositoryName = 'LeMill' #Change it if you make other LeMills
10portalURL = context.portal_url()
11portal_oai= 'oai:%s:' % '/'.join(portalURL.replace('http://', '').split('\\')).split('/')[0].split(':')[0]
12lt = context.lemill_tool
13t=lt.getTime()
14
15
16result=[]
17
18DECODER = 'utf-8'
19
20specialData = context.lemill_tool.getDataForOAIPMH()
21set = specialData['set']
22quote = specialData['quote']
23unquote = specialData['unquote']
24utctime = specialData['utcdatetime']
25
26ERROR_badArgument             = 'badArgument'
27ERROR_badResumptionToken      = 'badResumptionToken'
28ERROR_badVerb                 = 'badVerb'
29ERROR_cannotDisseminateFormat = 'cannotDisseminateFormat'
30ERROR_idDoesNotExist          = 'idDoesNotExist'
31ERROR_noRecordsMatch          = 'noRecordsMatch'
32ERROR_noMetadataFormats       = 'noMetadataFormats'
33ERROR_noSetHierarchy          = 'noSetHierarchy'
34
35tg = {}
36tg['pre-school education'] = ('U-6', 'LOMv1.0', 'learner', 'LREv3.0', 'pre-school')
37tg['1st grade'] = ('6-8', 'LOMv1.0', 'learner', 'LREv3.0', 'compulsory education')
38tg['2nd grade'] = ('7-9', 'LOMv1.0', 'learner', 'LREv3.0', 'compulsory education')
39tg['3rd grade'] = ('8-10', 'LOMv1.0', 'learner', 'LREv3.0', 'compulsory education')
40tg['4th grade'] = ('9-11', 'LOMv1.0', 'learner', 'LREv3.0', 'compulsory education')
41tg['5th grade'] = ('10-12', 'LOMv1.0', 'learner', 'LREv3.0', 'compulsory education')
42tg['6th grade'] = ('11-13', 'LOMv1.0', 'learner', 'LREv3.0', 'compulsory education')
43tg['7th grade'] = ('12-14', 'LOMv1.0', 'learner', 'LREv3.0', 'compulsory education')
44tg['8th grade'] = ('13-15', 'LOMv1.0', 'learner', 'LREv3.0', 'compulsory education')
45tg['9th grade'] = ('14-16', 'LOMv1.0', 'learner', 'LREv3.0', 'compulsory education')
46tg['10th grade'] = ('15-17', 'LOMv1.0', 'learner', 'LREv3.0', 'compulsory education')
47tg['11th grade'] = ('16-18', 'LOMv1.0', 'learner', None, None)
48tg['12th grade'] = ('17-19', 'LOMv1.0', 'learner', None, None)
49tg['higher education'] = ('18-U', 'LOMv1.0', 'learner', 'LOMv1.0', 'higher education')
50tg['adult education'] = ('18-U', 'LOMv1.0', 'learner', 'LREv3.0', 'continuing education')
51tg['teachers'] = ('21-U', 'LOMv1.0', 'teacher', None, None)
52tg['special education'] = ('6-19', 'LOMv1.0', 'learner', 'LREv3.0', 'special education')
53
54sa = {}
55sa['Natural sciences'] = (875, 'natural sciences')
56sa['Geography'] = (540, 'geography')
57sa['Chemistry'] = (195, 'chemistry')
58sa['Physics'] = (978, 'physics')
59sa['Biology'] = (144, 'biology')
60sa['Environmental education'] = (431, 'environmental education')
61sa['Language and literature'] = (707, 'language and literature')
62sa['Foreign languages'] = (508, 'foreign language')
63sa['Mathematics'] = (790, 'mathematics')
64sa['Informatics or ICT'] = (650, 'informatics')
65sa['Art'] = (91, 'art')
66sa['Music'] = (856, 'music')
67sa['History'] = (590, 'history')
68sa['Religion'] = (1085, 'religion')
69sa['Philosophy'] = (968, 'philosophy')
70sa['Ethics'] = (441, 'ethics')
71sa['Psychology'] = (1040, 'psychology')
72sa['Social sciences'] = (1204, 'social sciences')
73sa['Culture'] = (303, 'culture')
74sa['Citizenship'] = (209, 'citizenship')
75sa['Politics'] = (1001, 'politics')
76sa['Economics'] = (383, 'economics')
77sa['Media education'] = (798, 'media education')
78sa['Physical education'] = (974, 'physical education')
79sa['School-community relationship'] = (1139, 'school-community relationship')
80sa['Educational administration'] = (186, 'central adminisration')
81sa['Cross-curricular education'] = (292, 'cross-curricular education')
82
83# To increase speed we should cache user_id : nicename -mappings.
84name_cache={}
85def getNicename(user_id):
86    if user_id in name_cache:
87        return name_cache[user_id]
88    else:
89        userMD = context.getSearchObject(portal_type = 'MemberFolder', getState = ['public', 'draft'], getId = user_id)
90        if userMD:
91            userMD=userMD[0]
92            nn=userMD.getNicename
93        else:
94            nn=user_id
95        name_cache[user_id]=nn
96        return nn
97
98# also to increase speed we should have cache of collection ids
99d=lt.getTime()
100collection_cache=dict([(col.UID, col.getId) for col in context.getSearchObject(portal_type='Collection', getState='public')])
101lt.dumpMe('building collection cache:' + str(lt.getTime()-d))
102
103def IsThereResumptionTokenError(args):
104    return False
105
106def IsThereArgumentError(args, requiredArguments = (), optionalArguments = (), exclusiveArguments= ()):
107    foundRequiredArguments = []
108    if len(args)>1 and args.keys()[0] in exclusiveArguments:
109        return True
110    elif len(args)==1 and args.keys()[0] in exclusiveArguments:
111        return False
112    for arg in args:
113        if arg in requiredArguments:
114            foundRequiredArguments.append(arg)                       
115        elif arg not in optionalArguments:
116            return True
117    if set(foundRequiredArguments) != set(requiredArguments):
118        return True
119    return False
120
121def GetVerbAndArgumentsFromItems(items):
122    verb = None
123    args = {}
124    for t in items:
125        if t[0] != 'verb':
126            args[t[0]] = unquote(t[1])
127        else:
128            verb = t[1]
129    return verb, args
130
131def GenerateOAIIdentifierFromObject(obj):
132    return '%s%s' % (portal_oai, obj.getId)
133
134def GenerateIdentifierFromOAIIdentifier(id):
135    return id.split(':')[-2:]
136
137def GenerateDateString(d):
138    return d.strftime('%Y-%m-%d')
139
140def GenerateUTCDateString(d):
141    return d.strftime('%Y-%m-%dT%H:%M:%SZ')
142
143
144REQUEST = context.REQUEST
145REQUEST.RESPONSE.setHeader('Content-Type', 'text/xml;charset=UTF-8')
146verb, args = GetVerbAndArgumentsFromItems(REQUEST.form.items())
147verbList = ('Identify', 'ListMetadataFormats', 'ListSets', 'GetRecord', 'ListIdentifiers', 'ListRecords')
148supportedMetadataPrefixes   = ('oai_lom', 'oai_dc')
149supportedMetadataSchemas    = ('http://ltsc.ieee.org/xsd/lomv1.0/lom.xsd', 'http://www.openarchives.org/OAI/2.0/oai_dc.xsd')
150supportedMetadataNamespaces = ('http://ltsc.ieee.org/xsd/LOM', 'http://www.openarchives.org/OAI/2.0/oai_dc/')
151oai_lom_prefix=u"""
152
153"""
154oai_dc_prefix=u"""<OAI-PMH xmlns="http://www.openarchives.org/OAI/2.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/ http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd">"""
155
156
157errorVerb = verb not in verbList
158errorResumption = False
159errorArgs = False
160
161if verb == 'GetRecord': # GetRecord
162    errorArgs = IsThereArgumentError(args, ('identifier', 'metadataPrefix'))
163elif verb == 'Identify': # Identify
164    errorArgs = IsThereArgumentError(args)
165elif verb == 'ListIdentifiers': # ListIdentifiers
166    errorResumption = IsThereResumptionTokenError(args)
167    if not errorResumption:
168        errorArgs = IsThereArgumentError(args, ('metadataPrefix',), ('from', 'until', 'set', 'resumptionToken'))
169elif verb == 'ListMetadataFormats': #ListMetadataFormats
170    errorArgs = IsThereArgumentError(args, optionalArguments = ('identifier',))
171elif verb == 'ListRecords': #ListRecords
172    errorResumption = IsThereResumptionTokenError(args)
173    if not errorResumption:
174        errorArgs = IsThereArgumentError(args, ('metadataPrefix',), ('from', 'until', 'set'),  ('resumptionToken',))
175elif verb == 'ListSets': #ListSets
176    errorResumption = IsThereResumptionTokenError(args)
177    if not errorResumption:
178        errorArgs = IsThereArgumentError(args, optionalArguments = ('resumptionToken',))
179
180
181
182def getCollections(obj):
183    res = []
184    q = { 'targetUID': obj.UID, 'relationship':'relatesToContent'}
185    qres = context.reference_catalog(q)
186    for q in qres:
187        col_id=collection_cache.get(q.sourceUID, '')
188        if col_id:
189            res.append(col_id)
190    return res
191
192
193
194
195def GenerateIdentify():
196    result.append('<repositoryName>%s</repositoryName><baseURL>%s/OAI-script</baseURL><protocolVersion>2.0</protocolVersion>' % (repositoryName, portalURL))
197    lutool = getToolByName(context, 'lemill_usertool')
198    result.append('<adminEmail>%s</adminEmail>' % context.email_from_address)
199    result.append('<earliestDatestamp>1990-02-01T12:00:00Z</earliestDatestamp><deletedRecord>transient</deletedRecord><granularity>YYYY-MM-DDThh:mm:ssZ</granularity><description><oai-identifier xmlns="http://www.openarchives.org/OAI/2.0/oai-identifier" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai-identifier http://www.openarchives.org/OAI/2.0/oai-identifier.xsd"><scheme>oai</scheme>')
200    repositoryID = '/'.join(portalURL.replace('http://', '').split('\\')).split('/')[0].split(':')[0]
201    result.append('<repositoryIdentifier>%s</repositoryIdentifier><delimiter>:</delimiter>' % repositoryID)
202    d = DateTime()
203    result.append('<sampleIdentifier>oai:%s:%s</sampleIdentifier></oai-identifier></description>' % (repositoryID, str(d.millis())))
204
205
206def GenerateOneHeader(material, latestEditDate = None, collectionIDArray = None, method=None):
207    result.append('<header>')
208    result.append(''.join(('<identifier>',portal_oai, material.getId,'</identifier>')))
209    if not latestEditDate:
210        latestEditDate = material.getLatestEdit
211    result.append(''.join(('<datestamp>',GenerateDateString(latestEditDate),'</datestamp>')))
212    for collectionID in getCollections(material):
213        result.append(''.join(('<setSpec>',collectionID,'</setSpec>')))
214    result.append('</header>')
215
216
217
218
219def GetMax(list, values):   
220    for value in list:
221        if value in values:
222            return value
223    return list[-1]
224
225
226
227def BodyTextToDescription(obj):
228    return html_quote(obj.Title)
229#    bodyText = obj.getBodyText[0]
230#    if isinstance(bodyText, str) and not obj.isUid(bodyText):
231#        return bodyText
232#    for text in bodyText:
233#        if not obj.isUid(text):
234#            return text
235
236dc_type_mapping={'PresentationMaterial': 'presentation','MultimediaMaterial':'text','PILOTMaterial': 'video','ExerciseMaterial': 'educational game', 'LessonPlan': 'lesson plan','SchoolProjectMaterial': 'project'}
237
238
239def GenerateDublinCoreMetadata(obj):
240    language = obj.Language or 'en'
241    if same_type(language, []):
242        language=language[0]
243    result.append(''.join(('<oai_dc:dc xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd"><dc:title>',html_quote(obj.Title),'</dc:title>')))
244    creator = obj.Creator
245    result.append(''.join(('<dc:creator>',html_quote(creator),'</dc:creator>')))
246    for tag in obj.getTags:
247        result.append(''.join(('<dc:subject>',html_quote(tag),'</dc:subject>')))
248    result.append(''.join(('<dc:description>',BodyTextToDescription(obj),'</dc:description>')))
249    for author in obj.listCreators:
250        if author != creator:
251            result.append(''.join(('<dc:contributor>',html_quote(author),'</dc:contributor>')))
252    result.append(''.join(('<dc:date>',GenerateDateString(DateTime(obj.CreationDate)),'</dc:date>')))
253    result.append(''.join(('<dc:type>', dc_type_mapping[obj.portal_type],'</dc:type>')))
254    result.append(''.join(('<dc:format>text/html</dc:format><dc:identifier>',obj.getId,'</dc:identifier><dc:source>',portalURL,'</dc:source><dc:language>',language,'</dc:language>')))
255    result.append('<dc:rights>Creative Commons Attribution-ShareAlike 2.5 license: http://creativecommons.org/licenses/by-sa/2.5/</dc:rights>')
256    result.append('</oai_dc:dc>')
257
258endUserRoleSources=['LOMv1.0', '', None]
259endUserRoles=['teacher', 'learner','',None]
260contextSourceTypes=['LREv3.0', 'LOMv1.0', '',None]
261contexts=[ 'continuing education','special education','higher education','compulsory education','pre-school','',None]
262
263def GenerateLOMMetadata(obj):
264    language = obj.Language or 'en'
265    if same_type(language, []):
266        language=language[0]
267    result.append('<lom xmlns="http://ltsc.ieee.org/xsd/LOM" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ltsc.ieee.org/xsd/lomv1.0/lom.xsd http://ltsc.ieee.org/xsd/LOM">')
268    result.append(''.join(('<general><identifier><catalog>lemill.net</catalog><entry>', str(obj.getId),':',obj.UID,'</entry></identifier><title><string language="',language,'">',html_quote(obj.Title),'</string></title><language>',language,'</language><description><string language="',language,'">',BodyTextToDescription(obj),'</string></description>')))
269    keywords = obj.getTags
270    for keyword in keywords:
271        result.append(''.join(('<keyword><string language="',language,'">',html_quote(keyword),'</string></keyword>')))
272    result.append('</general><lifeCycle><version><string language="de">1.0</string></version><status><source>LOMv1.0</source><value>final</value></status>')
273    for author in obj.listCreators:
274        nn=getNicename(author)
275        if nn:
276            try:
277                names=nn.split(' ')
278                names.reverse()
279                names=';'.join(names)
280            except AttributeError:
281                names=''
282                nn=''
283            result.append(''.join(('<contribute><role><source>LOMv1.0</source><value>author</value></role><entity>BEGIN:VCARD\nVERSION:3.0\nN:',html_quote(names),';;;\nFN:',html_quote(nn),'\nEND:VCARD</entity></contribute>')))
284
285    result.append(''.join(('</lifeCycle><metaMetadata><identifier><catalog>oai</catalog><entry>',obj.getId,'</entry></identifier><language>',language,'</language><metadataSchema>LREv3.0</metadataSchema></metaMetadata><technical><location>',obj.getURL(),'</location></technical><educational>')))
286    result.append('<learningResourceType><source>LREv3.0</source>')
287    result.append(''.join(('<value>',dc_type_mapping[obj.portal_type],'</value></learningResourceType>' )))
288    intendedEndUserRoleSources = []
289    intendedEndUserRoleValues = []
290    contextSources = []
291    contextValues = []
292    for targetGroup in obj.getTarget_group:
293        tg_val=tg.get(targetGroup, None)
294        if tg_val:
295            age_range, role_source, role_value, context_source, context_value = tg_val
296            intendedEndUserRoleSources.append(role_source)
297            intendedEndUserRoleValues.append(role_value)
298            contextSources.append(context_source)
299            contextValues.append(context_value)
300            if age_range:
301                result.append(''.join(('<typicalAgeRange><string language="x-t-lre">',age_range,'</string></typicalAgeRange>')))
302    intendedEndUserRoleSource = GetMax(endUserRoleSources, intendedEndUserRoleSources)
303    intendedEndUserRoleValue = GetMax(endUserRoles, intendedEndUserRoleValues)
304    contextSource = GetMax(contextSourceTypes, contextSources)
305    contextValue = GetMax(contexts, contextValues)
306    if intendedEndUserRoleSource and intendedEndUserRoleValue:
307        result.append(''.join(('<intendedEndUserRole><source>',intendedEndUserRoleSource,'</source><value>', intendedEndUserRoleValue,'</value></intendedEndUserRole>')))
308    if contextSource and contextValue:
309        result.append(''.join(('<context><source>',contextSource,'</source><value>',contextValue,'</value></context>')))
310    result.append('</educational><rights><cost><source>LOMv1.0</source><value>no</value></cost><copyrightAndOtherRestrictions><source>LOMv1.0</source><value>yes</value></copyrightAndOtherRestrictions><description><string language="x-t-cc-url">http://creativecommons.org/licenses/by-sa/2.5/</string><string language="en">Creative Commons Attribution-ShareAlike 2.5 license</string></description></rights>')
311    subjectAreaList = obj.getSubject_area
312    if subjectAreaList:
313        result.append('<classification><purpose><source>LOMv1.0</source><value>discipline</value></purpose><taxonPath><source><string language="en">LRE Thesaurus</string></source>')
314        for subjectArea in subjectAreaList:
315            subj_id, subj_title = sa.get(subjectArea,('',''))
316            if subj_id:
317                result.append(''.join(('<taxon><id>',str(subj_id),'</id><entry><string language="en">',subj_title,'</string></entry></taxon>')))
318        result.append('</taxonPath></classification>')
319    result.append('</lom>')
320
321
322def GetOneRecord():
323    if args['metadataPrefix'] == 'oai_lom':
324        method=GenerateLOMMetadata
325    elif args['metadataPrefix'] == 'oai_dc':
326        method=GenerateDublinCoreMetadata
327    else:
328        result.pop()
329        raise ERROR_cannotDisseminateFormat
330    material = context.getSearchObject(portal_type = context.getMaterialTypes(no_references=True), getState = ['public', 'draft'], getId = GenerateIdentifierFromOAIIdentifier(args['identifier']))
331    if not material:
332        result.pop()
333        raise ERROR_idDoesNotExist
334    material = material[0]
335    GetRecord(material, method)
336
337
338def GetRecord(material, method):
339    result.append('<record>')
340    GenerateOneHeader(material)
341    result.append('<metadata>')
342    method(material)
343    result.append('</metadata>')
344    result.append('</record>')
345
346
347def GenerateHeaders(wrapper=GenerateOneHeader):
348    def getUidsFromCollection(coll_id):
349        collection=context.getSearchObject(getId=args['set'], portal_type='Collection', getState='public')
350        if not collection:
351            result.pop()
352            raise ERROR_idDoesNotExist
353        collection=collection[0].getObject()
354        return [x.UID() for x in collection.getContent() if x.portal_type in context.getMaterialTypes(no_references=True)]
355
356    query = {'portal_type':context.getMaterialTypes(no_references=True), 'getState':['public','draft']}   
357
358    if args.has_key('resumptionToken'):
359        argres = args['resumptionToken'].split(',')
360        try:
361            start=argres.pop(0)
362            restoken=[start]
363            start=int(start)
364            prefix=argres.pop(0)
365            if prefix=='oai_lom':
366                method=GenerateLOMMetadata
367            elif prefix=='oai_dc':
368                method=GenerateDublinCoreMetadata
369            else:
370                raise ERROR_badResumptionToken
371            restoken.append(prefix)
372            from_date=until_date=''
373            for token in argres: # optional tokens
374                if token.startswith('f'):
375                    from_date=DateTime(token[1:])
376                elif token.startswith('u'):
377                    until_date=DateTime(token[1:])
378                elif token.startswith('s'):
379                    uids=getUidsFromCollection(token[1:])
380                    query['UID']=uids
381                else:
382                    raise ERROR_badResumptionToken
383                restoken.append(token)
384            if from_date and until_date:
385                    query['created']=[from_date, until_date]
386                    query['created_usage']='range:min:max'
387            elif from_date:
388                    query['created']=from_date
389                    query['created_usage']='range:min'
390            elif until_date:
391                    query['created']=until_date
392                    query['created_usage']='range:max'
393        except:
394            result.pop()
395            raise ERROR_badResumptionToken
396    else:
397        start=0
398        restoken=[str(start)]
399        if args['metadataPrefix'] == 'oai_lom':
400            method=GenerateLOMMetadata
401            restoken.append('oai_lom')
402        elif args['metadataPrefix'] == 'oai_dc':
403            method=GenerateDublinCoreMetadata
404            restoken.append('oai_dc')
405        else:
406            result.pop()
407            raise ERROR_cannotDisseminateFormat
408        if args.has_key('from') and args.has_key('until'):       
409            try:
410                query['created']=[DateTime(args['from']), DateTime(args['until'])]
411                query['created_usage']='range:min:max'
412                restoken.append('f%s' % args['from'])
413                restoken.append('u%s' % args['until'])
414            except:
415                result.pop()
416                raise ERROR_badArgument
417        elif args.has_key('from'):
418            try:
419                query['created']=DateTime(args['from'])
420                query['created_usage']='range:min'
421                restoken.append('f%s' % args['from'])
422            except:
423                result.pop()
424                raise ERROR_badArgument
425        elif args.has_key('until'):
426            try:
427                query['created']=DateTime(args['until'])
428                query['created_usage']='range:max'
429                restoken.append('u%s' % args['until'])
430            except:
431                result.pop()
432                raise ERROR_badArgument
433        if args.has_key('set'):
434            query['UID']=getUidsFromCollection(args['set'])       
435            restoken.append('s%s' % args['set'])
436    results=context.getSearchObject(**query)
437    if start>len(results):
438        result.pop()
439        raise ERROR_badResumptionToken
440    end=start+1000
441    for material in results[start:end]:
442        try:
443            wrapper(material, method=method) # wrapper is usually GetRecord or GenerateOneHeader
444        except UnicodeDecodeError:
445            raise 'Unicode decode problem with resource %s' % str(material.getId)
446    lt.dumpMe('Contains %s results' % len(results))
447    if not results:
448        result.pop()
449        raise ERROR_noRecordsMatch
450    if start or len(results)>end:
451        ResumptionToken(restoken, completeListSize=len(results), cursor=min((end, len(results))))
452   
453
454def ResumptionToken(restoken, completeListSize, cursor):
455    if completeListSize==cursor:
456        token=''
457    else:
458        restoken[0]=str(cursor)
459        token=','.join(restoken)
460    result.append(''.join(('<resumptionToken completeListSize="',str(completeListSize),'" cursor="',str(cursor),'">',token,'</resumptionToken>')))
461
462
463def GenerateRecords():
464    GenerateHeaders(wrapper=GetRecord)
465
466def ListMetadataFormats():
467    if args.has_key('identifier'):
468        materials = context.getSearchObject(portal_type = context.getMaterialTypes(no_references=True), getState = ['public', 'draft'], getId = GenerateIdentifierFromOAIIdentifier(args['identifier']))
469        if len(materials) == 0:
470            result.pop()
471            raise ERROR_idDoesNotExist
472    for prefix, schema, namespace in zip(supportedMetadataPrefixes, supportedMetadataSchemas, supportedMetadataNamespaces):
473        result.append(''.join(('<metadataFormat><metadataPrefix>',prefix,'</metadataPrefix><schema>',schema,'</schema><metadataNamespace>',namespace,'</metadataNamespace></metadataFormat>')))
474
475def ListCollections():
476    results=context.getSearchObject(portal_type = 'Collection', getState='public')   
477    start=int(args.get('resumptionToken',0))
478    if start>len(results):
479        result.pop()
480        raise ERROR_badResumptionToken
481    end=start+1000
482    for collection in results[start:end]:
483        result.append(''.join(('<set><setSpec>',collection.getId,'</setSpec><setName>',html_quote(collection.Title),'</setName></set>')))
484    if start or len(results)>end:
485        ResumptionToken([0], completeListSize=len(results), cursor=min((end, len(results))))
486
487
488result.append('<?xml version="1.0" encoding="UTF-8" ?><OAI-PMH xmlns="http://www.openarchives.org/OAI/2.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/ http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd"><responseDate>%s</responseDate><request' % utctime)
489if not errorArgs:
490    for key, value in REQUEST.form.items():
491        if key != '-C':
492            result.append(' %s="%s"' % (key, value))
493result.append('>%s/OAI-script</request>' % context.aq_parent.absolute_url())
494
495
496try:
497    if errorVerb:
498        raise ERROR_badVerb
499    if errorArgs:
500        raise ERROR_badArgument
501    if errorResumption:
502        raise ERROR_badResumptionToken
503
504    result.append('<%s>' % verb)
505    if verb=='GetRecord':
506        GetOneRecord()
507    elif verb=='Identify':
508        GenerateIdentify()
509    elif verb=='ListIdentifiers':
510        GenerateHeaders()
511    elif verb=='ListMetadataFormats':
512        ListMetadataFormats()
513    elif verb=='ListRecords':
514        GenerateRecords()
515    elif verb=='ListSets':
516        ListCollections()
517    result.append('</%s>' % verb)
518
519except ERROR_badArgument:
520    result.append('<error code="%s">The request includes illegal arguments, is missing required arguments, includes a repeated argument, or values for arguments have an illegal syntax.</error>' % ERROR_badArgument)
521except ERROR_badResumptionToken:
522    result.append('<error code="%s">The value of the resumptionToken argument is invalid or expired.</error>' % ERROR_badResumptionToken)
523except ERROR_badVerb:
524    result.append('<error code="%s">Value of the verb argument is not a legal OAI-PMH verb, the verb argument is missing, or the verb argument is repeated.</error>' % ERROR_badVerb)
525except ERROR_cannotDisseminateFormat:
526    result.append('<error code="%s">The metadata format identified by the value given for the metadataPrefix argument is not supported by the item or by the repository.</error>' % ERROR_cannotDisseminateFormat)
527except ERROR_idDoesNotExist:
528    result.append('<error code="%s">The value of the identifier argument is unknown or illegal in this repository.</error>' % ERROR_idDoesNotExist)
529except ERROR_noRecordsMatch:
530    result.append('<error code="%s">The combination of the values of the from, until, set and metadataPrefix arguments results in an empty list.</error>' % ERROR_noRecordsMatch)
531except ERROR_noMetadataFormats:
532    result.append('<error code="%s">There are no metadata formats available for the specified item.</error>' % ERROR_noMetadataFormats)
533except ERROR_noSetHierarchy:
534    result.append('<error code="%s">The repository does not support sets.</error>' % ERROR_noSetHierarchy)
535
536result.append('</OAI-PMH>')
537lt.dumpMe('Building this took:'+str(lt.getTime()-t))
538return u'\n'.join([r.decode('utf-8') for r in result]).encode('utf-8')
Note: See TracBrowser for help on using the repository browser.