]> git.parisson.com Git - telemeta.git/commitdiff
#67: couple OAI-PMH subsystem with models and web view
authorolivier <>
Mon, 6 Apr 2009 16:10:30 +0000 (16:10 +0000)
committerolivier <>
Mon, 6 Apr 2009 16:10:30 +0000 (16:10 +0000)
telemeta/interop/oaidatasource.py [new file with mode: 0644]
telemeta/models/dublincore.py
telemeta/models/media.py
telemeta/models/query.py
telemeta/urls.py
telemeta/web/base.py

diff --git a/telemeta/interop/oaidatasource.py b/telemeta/interop/oaidatasource.py
new file mode 100644 (file)
index 0000000..be9bd13
--- /dev/null
@@ -0,0 +1,67 @@
+from telemeta.models import MediaCollection, MediaItem, Revision
+from datetime import datetime
+
+class TelemetaOAIDataSource(object):
+    """Telemeta OAI datasource adapter. This class implements the oai.IDataSource interface."""
+
+    def get_earliest_time(self):
+        """Return the change time of the oldest record(s) as a datetime object"""
+        try:
+            rev = Revision.objects.order_by('time')[0]
+            return rev.time
+        except IndexError:
+            return datetime.now()
+
+    def prepare_record(self, type, record):
+        ctime = record.get_revision().time
+        dc = []
+        _dc = record.to_dublincore().to_list()
+        for k, v in _dc:
+            if k == 'identifier':
+                dc.append((k, type + ':' + v))
+            else:
+                dc.append((k, v))
+        return (dc, ctime)
+
+    def get_record(self, id):
+        """Return a specific record"""
+        type, id = id.split(':')
+        if (type == 'collection'):
+            record  = MediaCollection.objects.get(id=id)
+        elif (type == 'item'):
+            record = MediaItem.objects.get(id=id)
+        else:
+            raise Exception("No such record type: %s" % type)
+
+        return self.prepare_record(type, record)
+
+
+    def count_records(self, from_time = None, until_time = None):
+        """Must return the number of records between (optional) from and until change time."""
+        nitems = MediaItem.objects.by_change_time(from_time, until_time).count()
+        ncolls = MediaCollection.objects.by_change_time(from_time, until_time).count()
+        return nitems + ncolls
+
+    def list_records(self, offset, limit, from_time = None, until_time = None):
+        """Return a list of records"""
+
+        result = []
+
+        query = MediaItem.objects.by_change_time(from_time, until_time)
+        nitems = query.count()
+        if (offset < nitems):
+            set = query[offset:offset + limit]
+            for record in set:
+                result.append(self.prepare_record('item', record))
+            limit -= len(set)
+            offset = 0
+        else:
+            offset -= nitems
+
+        if limit > 0:
+            query = MediaCollection.objects.by_change_time(from_time, until_time)
+            set = query[offset:offset + limit]
+            for record in set:
+                result.append(self.prepare_record('collection', record))
+            
+        return result
index e3062d340c6a61d64f9b044875a0549bf36d96b6..ef00030df2cab856835c7b177f3e632d93f03151 100644 (file)
@@ -30,6 +30,14 @@ class Resource(object):
                 result[element.name] = unicode(element.value)
         return result
 
+    def to_list(self):
+        """Convert the resource to unqualified dublin core, as a list of the form:
+           [(key, value), ...]"""
+        result = []
+        for element in self.elements:
+            result.append((element.name, unicode(element.value)))
+        return result
+
 class Element(object):
     "Represent a Dublin Core element"
 
index 2b50c35572d2f466064675d4b55876a51ff24ae4..1a818cdbe18cac117390c112522911344affd1f9 100644 (file)
@@ -191,6 +191,9 @@ class MediaCollection(Model, MediaCore):
         super(MediaCollection, self).save(force_insert, force_update)
         Revision(element_type='collection', element_id=self.id).touch()
         
+    def get_revision(self):
+        return Revision.objects.filter(element_type='collection', element_id=self.id).order_by('-time')[0]
+
     class Meta:
         app_label = 'telemeta'
         ordering = ['title']
@@ -280,6 +283,9 @@ class MediaItem(Model, MediaCore):
 
         return duration
 
+    def get_revision(self):
+        return Revision.objects.filter(element_type='item', element_id=self.id).order_by('-time')[0]
+
     def __unicode__(self):
         return self.title
 
@@ -326,6 +332,9 @@ class MediaPart(Model, MediaCore):
         super(MediaPart, self).save(force_insert, force_update)
         Revision(element_type='part', element_id=self.id).touch()
 
+    def get_revision(self):
+        return Revision.objects.filter(element_type='part', element_id=self.id).order_by('-time')[0]
+
     class Meta:
         app_label = 'telemeta'
         ordering = ['title']
@@ -336,8 +345,9 @@ class Revision(Model):
     element_type    = CharField(max_length=16, choices=(('collection', 'collection'),
                                                         ('item', 'item'),
                                                         ('part', 'part')))
-    element_id      = CharField(max_length=250)
-    change_type     = CharField(max_length=8, choices= (('create', 'create'),
+    element_id      = CharField(max_length=250, db_index=True)
+    change_type     = CharField(max_length=8, choices= (('import', 'import'),
+                                                        ('create', 'create'),
                                                         ('update', 'update'),
                                                         ('delete', 'delete')))
     time            = DateTimeField(auto_now_add=True)
index fa589d74996837432d178b69d61643ee7a2bee67..397b9098141b73a3df43638a3b20e830142fe547 100644 (file)
@@ -30,6 +30,15 @@ class CoreQuerySet(QuerySet):
         kwargs = {field + '__iregex': regex}
         return self.filter(**kwargs)
 
+    def _by_change_time(self, type, from_time = None, until_time = None):
+        where = ["element_type = '%s'" % type]
+        if from_time:
+            where.append("time >= '%s'" % from_time.strftime('%Y-%m-%d %H:%M:%S'))
+        if until_time:
+            where.append("time <= '%s'" % until_time.strftime('%Y-%m-%d %H:%M:%S'))
+        return self.extra(
+            where = ["id IN (SELECT DISTINCT element_id FROM telemeta_revision WHERE %s)" % " AND ".join(where)]);
+
 class CoreManager(Manager):
     "Base class for all models managers"
 
@@ -64,6 +73,9 @@ class MediaCollectionQuerySet(CoreQuerySet):
     def by_ethnic_group(self, group):
         return self.filter(items__ethnie_grsocial=group).distinct()
 
+    def by_change_time(self, from_time = None, until_time = None):
+        return self._by_change_time('collection', from_time, until_time)
+
 class MediaCollectionManager(CoreManager):
     "Manage collection queries"
 
@@ -88,6 +100,9 @@ class MediaCollectionManager(CoreManager):
     def by_ethnic_group(self, *args, **kwargs):
         return self.get_query_set().by_ethnic_group(*args, **kwargs)
 
+    def by_change_time(self, *args, **kwargs):
+        return self.get_query_set().by_change_time(*args, **kwargs)
+
     def stat_continents(self, order_by='num'):      
         "Return the number of collections by continents and countries as a tree"
         from django.db import connection
@@ -170,6 +185,9 @@ class MediaItemQuerySet(CoreQuerySet):
 
     def by_publish_date(self, pattern):
         return self.filter(collection__date_published__icontains=pattern) 
+
+    def by_change_time(self, from_time = None, until_time = None):
+        return self._by_change_time('item', from_time, until_time)
             
 class MediaItemManager(CoreManager):
     "Manage media items queries"
@@ -192,6 +210,9 @@ class MediaItemManager(CoreManager):
     def by_publish_date(self, *args, **kwargs):
         return self.get_query_set().by_publish_date(*args, **kwargs)
 
+    def by_change_time(self, *args, **kwargs):
+        return self.get_query_set().by_change_time(*args, **kwargs)
+
     def list_ethnic_groups(self):
         "Return a list of all ethnic groups"
         
index d54fa4353023401920efbb543b92d34fed9b01d0..7972430d9cdc8832aa46babec7e5676cbf98abcf 100644 (file)
@@ -135,4 +135,7 @@ urlpatterns = patterns('',
     url(r'^timeside/(?P<path>.*)$', 'django.views.static.serve', 
         {'document_root': htdocs+'/timeside'},
         name="telemeta-timeside"),
+
+    # OAI-PMH Data Provider
+    url(r'^oai/.*$', web_view.handle_oai_request, name="telemeta-oai")
 )
index 1371a6dd629e4ac7589ed4ec2f4536f947363d2e..f0b0bf5362fc47785a1304f956149c19a0aae1c5 100644 (file)
@@ -27,6 +27,8 @@ from telemeta.export import *
 from telemeta.visualization import *
 from telemeta.analysis import *
 from telemeta.analysis.vamp import *
+import telemeta.interop.oai as oai
+from telemeta.interop.oaidatasource import TelemetaOAIDataSource
 
 class WebView(Component):
     """Provide web UI methods"""
@@ -323,3 +325,12 @@ class WebView(Component):
             template_name='telemeta/geo_country_collections.html', paginate_by=20,
             extra_context={'country': country, 'continent': continent})
 
+    def handle_oai_request(self, request):
+        url = request.META['HTTP_HOST'] + request.path
+        datasource  = TelemetaOAIDataSource()
+        provider    = oai.DataProvider(datasource, "Telemeta", url, "admin@telemeta.org")
+        args = request.GET.copy()
+        args.update(request.POST)
+        return HttpResponse(provider.handle(args), mimetype='text/xml')
+        
+