]> git.parisson.com Git - telemeta.git/commitdiff
Fix backup and zip serializer call, cleanup
authorGuillaume Pellerin <yomguy@parisson.com>
Mon, 9 Mar 2015 16:54:07 +0000 (17:54 +0100)
committerGuillaume Pellerin <yomguy@parisson.com>
Mon, 9 Mar 2015 16:54:07 +0000 (17:54 +0100)
telemeta/backup/core.py
telemeta/core.py
telemeta/models/collection.py
telemeta/models/fields.py
telemeta/models/resource.py
telemeta/views/collection.py

index 395d7909834be6f3dafbe2f2d47aa9a2d77c77a4..208c67e600e6aad618f0353193a5f372599422ce 100644 (file)
@@ -41,11 +41,15 @@ import md5
 from django.conf import settings
 from telemeta.models import MediaItem
 
+
 class CollectionSerializer(object):
     """Provide backup-related features"""
 
-    def __init__(self, collection):
+    def __init__(self, collection, dest_dir='.'):
         self.collection = collection
+        self.coll_dir = dest_dir + "/" + str(self.collection.id)
+        if not os.path.exists(self.coll_dir):
+            os.makedirs(self.coll_dir)
 
     def __get_file_md5(self, path):
         "Compute the MD5 hash of a file (Python version of md5sum)"
@@ -62,32 +66,41 @@ class CollectionSerializer(object):
     def __get_media_filename(self, item):
         return str(item.id) + ".wav"
 
-    def store(self, dest_dir):
-        """Serialize and store the collection with related items and media
-        files into a subdirectory of the provided directory
-        """
-        coll_dir = dest_dir + "/" + str(self.collection.id)
-        os.mkdir(coll_dir)
-
-        xml = self.get_xml()
-        file = open(coll_dir + "/collection.xml", "wb")
-        file.write(xml.encode("utf-8"))
-        file.close()
-
+    def store_files(self):
         if self.collection.has_mediafile():
-            md5_file = open(coll_dir + "/MD5SUM", "wb")
+            md5_file = open(self.coll_dir + "/MD5SUM", "wb")
 
             items = self.collection.items.all()
             for item in items:
                 if item.file:
                     dst_basename = self.__get_media_filename(item)
-                    dst = coll_dir + "/" + dst_basename
+                    dst = self.coll_dir + "/" + dst_basename
                     shutil.copyfile(item.file.path, dst)
                     hash = self.__get_file_md5(dst)
                     md5_file.write(hash + "  " + dst_basename + "\n")
 
             md5_file.close()
 
+    def store_json(self, dest_dir):
+        """Serialize and store the collection with related items and media
+        files into a subdirectory of the provided directory
+        """
+        json = self.collection.get_json()
+        file = open(self.coll_dir + "/collection.json", "wb")
+        file.write(json)
+        file.close()
+        self.store_files()
+
+    def store_xml(self, dest_dir):
+        """Serialize and store the collection with related items and media
+        files into a subdirectory of the provided directory
+        """
+        xml = self.get_xml()
+        file = open(self.coll_dir + "/collection.xml", "wb")
+        file.write(xml.encode("utf-8"))
+        file.close()
+        self.store_files()
+
     def get_xml(self):
         """Return a string containing the XML representation of the collection
         and related items
@@ -110,12 +123,6 @@ class CollectionSerializer(object):
             item_doc.unlink()
         doc.normalize()
 
-        # libxml2 has prettier output than xml.dom:
-        tree = libxml2.parseDoc(doc.toxml(encoding="utf-8"))
-        doc.unlink()
-        xml = unicode(tree.serialize(encoding="utf-8", format=1), "utf-8")
-        tree.free()
-
-        return xml
+        return doc.toxml()
 
 
index 9d3a5058d234a0d5e20698744115e57eed7b739e..c708534af63a326d6c6d2e6d084367bf3283a60c 100644 (file)
 # All rights reserved.
 #
 # This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution. 
+# you should have received as part of this distribution.
 #
 # Author: Jonas Borgström <jonas@edgewall.com>
 #         Christopher Lenz <cmlenz@gmx.de>
 #         Olivier Guilyardi <olivier@samalyse.com>
 
-__all__ = ['Component', 'ExtensionPoint', 'implements', 'Interface',
-           'TelemetaError']
+__all__ = ['TelemetaError']
 
 
 class TelemetaError(Exception):
     """Exception base class for errors in Telemeta."""
     pass
-    
-class Interface(object):
-    """Marker base class for extension point interfaces."""
 
-
-class ExtensionPoint(property):
-    """Marker class for extension points in components."""
-
-    def __init__(self, interface):
-        """Create the extension point.
-        
-        @param interface: the `Interface` subclass that defines the protocol
-            for the extension point
-        """
-        property.__init__(self, self.extensions)
-        self.interface = interface
-        self.__doc__ = 'List of components that implement `%s`' % \
-                       self.interface.__name__
-
-    def extensions(self, component):
-        """Return a list of components that declare to implement the extension
-        point interface."""
-        extensions = ComponentMeta._registry.get(self.interface, [])
-        return filter(None, [component.compmgr[cls] for cls in extensions])
-
-    def __repr__(self):
-        """Return a textual representation of the extension point."""
-        return '<ExtensionPoint %s>' % self.interface.__name__
-
-
-class ComponentMeta(type):
-    """Meta class for components.
-    
-    Takes care of component and extension point registration.
-    """
-    _components = []
-    _registry = {}
-
-    def __new__(cls, name, bases, d):
-        """Create the component class."""
-
-        d['_implements'] = _implements[:]
-        del _implements[:]
-
-        new_class = type.__new__(cls, name, bases, d)
-        if name == 'Component':
-            # Don't put the Component base class in the registry
-            return new_class
-
-        # Only override __init__ for Components not inheriting ComponentManager
-        if True not in [issubclass(x, ComponentManager) for x in bases]:
-            # Allow components to have a no-argument initializer so that
-            # they don't need to worry about accepting the component manager
-            # as argument and invoking the super-class initializer
-            init = d.get('__init__')
-            if not init:
-                # Because we're replacing the initializer, we need to make sure
-                # that any inherited initializers are also called.
-                for init in [b.__init__._original for b in new_class.mro()
-                             if issubclass(b, Component)
-                             and '__init__' in b.__dict__]:
-                    break
-            def maybe_init(self, compmgr, init=init, cls=new_class):
-                if cls not in compmgr.components:
-                    compmgr.components[cls] = self
-                    if init:
-                        init(self)
-            maybe_init._original = init
-            new_class.__init__ = maybe_init
-
-        if d.get('abstract'):
-            # Don't put abstract component classes in the registry
-            return new_class
-
-        ComponentMeta._components.append(new_class)
-        for interface in d.get('_implements', []):
-            ComponentMeta._registry.setdefault(interface, []).append(new_class)
-        for base in [base for base in bases if hasattr(base, '_implements')]:
-            for interface in base._implements:
-                ComponentMeta._registry.setdefault(interface, []).append(new_class)
-
-        return new_class
-
-
-_implements = []
-
-def implements(*interfaces):
-    """Can be used in the class definiton of `Component` subclasses to declare
-    the extension points that are extended.
-    """
-    _implements.extend(interfaces)
-
-
-class Component(object):
-    """Base class for components.
-
-    Every component can declare what extension points it provides, as well as
-    what extension points of other components it extends.
-    """
-    __metaclass__ = ComponentMeta
-
-    def __new__(cls, *args, **kwargs):
-        """Return an existing instance of the component if it has already been
-        activated, otherwise create a new instance.
-        """
-        # If this component is also the component manager, just invoke that
-        if issubclass(cls, ComponentManager):
-            self = super(Component, cls).__new__(cls)
-            self.compmgr = self
-            return self
-
-        # The normal case where the component is not also the component manager
-        compmgr = args[0]
-        self = compmgr.components.get(cls)
-        if self is None:
-            self = super(Component, cls).__new__(cls)
-            self.compmgr = compmgr
-            compmgr.component_activated(self)
-        return self
-
-
-class ComponentManager(object):
-    """The component manager keeps a pool of active components."""
-
-    def __init__(self):
-        """Initialize the component manager."""
-        self.components = {}
-        self.enabled = {}
-        if isinstance(self, Component):
-            self.components[self.__class__] = self
-
-    def __contains__(self, cls):
-        """Return wether the given class is in the list of active components."""
-        return cls in self.components
-
-    def __getitem__(self, cls):
-        """Activate the component instance for the given class, or return the
-        existing the instance if the component has already been activated."""
-        if cls not in self.enabled:
-            self.enabled[cls] = self.is_component_enabled(cls)
-        if not self.enabled[cls]:
-            return None
-        component = self.components.get(cls)
-        if not component:
-            if cls not in ComponentMeta._components:
-                raise TelemetaError, 'Component "%s" not registered' % cls.__name__
-            try:
-                component = cls(self)
-            except TypeError, e:
-                raise TelemetaError, 'Unable to instantiate component %r (%s)' \
-                                 % (cls, e)
-        return component
-
-    def component_activated(self, component):
-        """Can be overridden by sub-classes so that special initialization for
-        components can be provided.
-        """
-
-    def is_component_enabled(self, cls):
-        """Can be overridden by sub-classes to veto the activation of a
-        component.
-
-        If this method returns False, the component with the given class will
-        not be available.
-        """
-        return True
index e3d640c723d276f3065967a8ce8690443cdc77e0..33626ed328df200186979f10ce03258d62c7f85e 100644 (file)
@@ -227,10 +227,15 @@ class MediaCollection(MediaResource):
         metadata['doc_status'] = self.document_status()
         metadata['countries'] = ';'.join([location.name for location in self.main_countries()])
         metadata['ethnic_groups'] = ';'.join([group.value for group in self.ethnic_groups()])
-        metadata['last_modification_date'] = unicode(self.get_revision().time)
+        revision = self.get_revision()
+        if revision:
+            metadata['last_modification_date'] = unicode(revision.time)
         metadata['computed_duration'] = unicode(self.computed_duration())
         metadata['computed_size'] = unicode(self.computed_size())
         metadata['number_of_items'] = unicode(self.items.all().count())
+        metadata['approx_duration'] = unicode(self.approx_duration)
+
+        print metadata
 
         i = 0
         for media in self.related.all():
@@ -263,6 +268,10 @@ class MediaCollection(MediaResource):
 
         return metadata
 
+    def get_json(self):
+        import json
+        return json.dumps(self.to_dict_with_more())
+
 
 class MediaCollectionRelated(MediaRelated):
     "Collection related media"
index d252b9a23bbdd08449394609d1270ce9f801929b..19aa6c8f779735f2d5fa6f0b0e10ff4a22b96928 100644 (file)
@@ -80,6 +80,9 @@ class Duration(object):
 
         return "%.2d:%.2d:%.2d" % (hours, minutes, seconds)
 
+    def __unicode__(self):
+        return self.__str__()
+
     @staticmethod
     def fromstr(str):
         if not str:
index 2b5d86777e69e724148617ca72a5f40cb969a7c5..f79c0b57fe3d668c85d34c05157df4d735eddc3b 100644 (file)
@@ -58,7 +58,11 @@ class MediaResource(ModelCore):
         Revision.touch(self, user)
 
     def get_revision(self):
-        return Revision.objects.filter(element_type=self.element_type, element_id=self.id).order_by('-time')[0]
+        revisions = Revision.objects.filter(element_type=self.element_type, element_id=self.id).order_by('-time')
+        if revisions:
+            return revisions[0]
+        else:
+            return None
 
     class Meta:
         abstract = True
index a6dca61ea6bb07aaf204ea52e24b9334f71436dc..8eb1696399758511ce6c2cf7be3f90888a45f9a8 100644 (file)
@@ -196,7 +196,13 @@ class CollectionPackageView(View):
         collection = self.get_object()
         serializer = CollectionSerializer(collection)
 
-        data = serializer.get_xml().encode("utf-8")
+        data = collection.get_json().encode('utf-8')
+        filename = collection.public_id + '.json'
+        cache_data.write_bin(data, filename)
+        path = cache_data.dir + os.sep + filename
+        z.write(path, arcname=collection.public_id + os.sep + filename)
+
+        data = serializer.get_xml().encode('utf-8')
         filename = collection.public_id + '.xml'
         cache_data.write_bin(data, filename)
         path = cache_data.dir + os.sep + filename