From: Guillaume Pellerin Date: Mon, 9 Mar 2015 16:54:07 +0000 (+0100) Subject: Fix backup and zip serializer call, cleanup X-Git-Tag: 1.6a^2~62 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=7d777800feebc3d3e8e39e65bd70ff09fd95555c;p=telemeta.git Fix backup and zip serializer call, cleanup --- diff --git a/telemeta/backup/core.py b/telemeta/backup/core.py index 395d7909..208c67e6 100644 --- a/telemeta/backup/core.py +++ b/telemeta/backup/core.py @@ -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() diff --git a/telemeta/core.py b/telemeta/core.py index 9d3a5058..c708534a 100644 --- a/telemeta/core.py +++ b/telemeta/core.py @@ -7,182 +7,16 @@ # 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 # Christopher Lenz # Olivier Guilyardi -__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 '' % 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 diff --git a/telemeta/models/collection.py b/telemeta/models/collection.py index e3d640c7..33626ed3 100644 --- a/telemeta/models/collection.py +++ b/telemeta/models/collection.py @@ -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" diff --git a/telemeta/models/fields.py b/telemeta/models/fields.py index d252b9a2..19aa6c8f 100644 --- a/telemeta/models/fields.py +++ b/telemeta/models/fields.py @@ -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: diff --git a/telemeta/models/resource.py b/telemeta/models/resource.py index 2b5d8677..f79c0b57 100644 --- a/telemeta/models/resource.py +++ b/telemeta/models/resource.py @@ -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 diff --git a/telemeta/views/collection.py b/telemeta/views/collection.py index a6dca61e..8eb16963 100644 --- a/telemeta/views/collection.py +++ b/telemeta/views/collection.py @@ -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