Changeset 1247 in products


Ignore:
Timestamp:
Aug 17, 2009 3:10:02 PM (17 years ago)
Author:
koval
Message:

now images are not moved to central folder on export

Location:
quintagroup.transmogrifier.simpleblog2quills/branches/without_image_move/quintagroup/transmogrifier/simpleblog2quills
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • quintagroup.transmogrifier.simpleblog2quills/branches/without_image_move/quintagroup/transmogrifier/simpleblog2quills/activator.py

    r638 r1247  
    77 
    88from Products.CMFCore import utils 
    9 from Products.CMFCore.WorkflowCore import WorkflowException 
    109 
    1110try: 
     
    1716    # plone 2.1, because zcml:condition attribute in zcml doesn't work 
    1817    pass 
    19  
    20 from quintagroup.transmogrifier.simpleblog2quills.adapters import IMAGE_FOLDER 
    2118 
    2219class BlogActivatorSection(object): 
     
    4643 
    4744            path = item[pathkey] 
    48             if type_ is None and newtype == 'Large Plone Folder': 
    49                 parts = path.rsplit('/', 1) 
    50                 if len(parts) == 2: 
    51                     parent, id_ = parts 
    52                 else: 
    53                     yield item; continue 
    54                 if id_ != IMAGE_FOLDER: 
    55                     yield item; continue 
    5645 
    5746            obj = self.context.unrestrictedTraverse(path, None) 
     
    6554                    alsoProvides(obj, IWeblogEnhanced) 
    6655                    event.notify(WeblogActivationEvent(obj)) 
    67             elif type_ is None and newtype == 'Large Plone Folder': 
    68                 # pulish 'images' subfolder 
    69                 parent = self.context.unrestrictedTraverse(parent, None) 
    70                 if IWeblogEnhanced.providedBy(parent) : 
    71                     try: 
    72                         self.wftool.doActionFor(obj, 'publish') 
    73                     except WorkflowException: 
    74                         pass 
    7556 
    7657            yield item 
  • quintagroup.transmogrifier.simpleblog2quills/branches/without_image_move/quintagroup/transmogrifier/simpleblog2quills/adapters.py

    r1241 r1247  
    11import re 
    22from xml.dom import minidom 
    3 from types import ListType 
    4 from types import TupleType 
    53 
    6 from zope.interface import implements, classProvides 
    7 from zope.app.annotation.interfaces import IAnnotations 
     4from zope.interface import implements 
    85 
    9 from Products.CMFPlone.Portal import PloneSite 
    106from Products.CMFCore import utils 
    11  
    12 from collective.transmogrifier.interfaces import ISection, ISectionBlueprint 
    13 from collective.transmogrifier.utils import defaultMatcher 
    147 
    158from quintagroup.transmogrifier.interfaces import IExportDataCorrector, IImportDataCorrector 
    169from quintagroup.transmogrifier.adapters.exporting import ReferenceExporter 
    17 from quintagroup.transmogrifier.manifest import ManifestExporterSection 
    18 from quintagroup.transmogrifier.logger import VALIDATIONKEY 
    1910 
    20 from quintagroup.transmogrifier.simpleblog2quills.interfaces import IExportItemManipulator, IBlog 
    21  
    22 # URL of the site, where blog is located (this is needed to fix links in entries) 
    23 SITE_URLS = [] 
    24 IMAGE_FOLDER = 'images' 
    25 IMAGE_FOLDER_TYPE = 'Large Plone Folder' 
    26 # this registries are needed to avoid loosing images with equal ids 
    27 IMAGE_IDS = [] 
    28 IMAGE_PATHS = {} 
    29  
    30 class BlogManifest(object): 
    31     implements(IExportDataCorrector) 
    32  
    33     def __init__(self, context): 
    34         self.context = context 
    35  
    36     def __call__(self, data): 
    37         # flag that indicated whether 'images' folder must added to manifest 
    38         need_to_add = True 
    39  
    40         doc = minidom.parseString(data['data']) 
    41         root = doc.documentElement 
    42         for child in root.getElementsByTagName('record'): 
    43             if child.getAttribute('type') not in  ('BlogEntry', 'BlogFolder'): 
    44                 root.removeChild(child) 
    45             elif str(child.firstChild.nodeValue.strip()) == IMAGE_FOLDER: 
    46                 # blog already contains object with IMAGE_FOLDER id 
    47                 need_to_add = False 
    48  
    49         if need_to_add: 
    50             folder = doc.createElement('record') 
    51             folder.setAttribute('type', IMAGE_FOLDER_TYPE) 
    52             folder.appendChild(doc.createTextNode(IMAGE_FOLDER)) 
    53             root.appendChild(folder) 
    54  
    55         data['data'] = doc.toxml('utf-8') 
    56         return data 
    57  
    58 class BlogFolderManifest(object): 
    59     implements(IExportDataCorrector) 
    60  
    61     def __init__(self, context): 
    62         self.context = context 
    63  
    64     def __call__(self, data): 
    65         doc = minidom.parseString(data['data']) 
    66         root = doc.documentElement 
    67         for child in root.getElementsByTagName('record'): 
    68             if child.getAttribute('type') not in  ('BlogEntry', 'BlogFolder'): 
    69                 root.removeChild(child) 
    70         data['data'] = doc.toxml('utf-8') 
    71         return data 
     11from quintagroup.transmogrifier.simpleblog2quills.interfaces import IExportItemManipulator 
    7212 
    7313class BlogEntryManifest(object): 
     
    8323        return item 
    8424 
    85 def recurseToInterface(item, ifaces): 
    86     """Recurse up the aq_chain until an object providing `iface' is found, 
    87     and return that. 
    88     """ 
    89     if not isinstance(ifaces, (ListType, TupleType)): 
    90         ifaces = [ifaces] 
    91     parent = item.aq_parent 
    92     for iface in ifaces: 
    93         if iface.providedBy(item): 
    94             return item 
    95     for iface in ifaces: 
    96         if iface.providedBy(parent): 
    97             return parent 
    98     if isinstance(parent, PloneSite): 
    99         # Stop when we get to the portal root. 
    100         return None 
    101     return recurseToInterface(parent, ifaces) 
    102  
    103 def getUniqueId(image_id): 
    104     """ Generate id that is unique in IMAGE_IDS registry. 
    105     """ 
    106     if '.' in image_id: 
    107         name, ext = image_id.rsplit('.', 1) 
    108         ext = '.' + ext 
    109     else: 
    110         name, ext = image_id, '' 
    111     if image_id in IMAGE_IDS: 
    112         c = 1 
    113         new_id = name + str(c) + ext 
    114         while new_id in IMAGE_IDS: 
    115             c += 1 
    116             new_id = name + str(c) + ext 
    117         image_id = new_id 
    118  
    119     return image_id 
    120  
    12125class BlogEntryExporter(ReferenceExporter): 
    12226    implements(IExportDataCorrector) 
     
    12832        self.portal_url = utils.getToolByName(self.context, 'portal_url') 
    12933        self.portal = self.portal_url.getPortalObject() 
     34 
     35        # try to get site domain (maybe it's stored  
     36        # in portal_properties/site_properties/title property) 
     37        self.site_domains = [] 
     38        portal_properties = utils.getToolByName(self.context, 'portal_properties') 
     39        domain = portal_properties.site_properties.getProperty('title') 
     40        if domain is not None: 
     41            if domain.startswith('www.'): 
     42                self.site_domains.append(domain) 
     43            else: 
     44                self.site_domains.append(domain) 
     45                self.site_domains.append('www.' + domain) 
    13046 
    13147    def __call__(self, data): 
     
    13955        text = elem.firstChild.nodeValue 
    14056        urls = self.SRC.findall(text) 
    141         blog = recurseToInterface(self.context, IBlog) 
    142         blog_path = blog.getPhysicalPath() 
    14357        context_path = self.context.getPhysicalPath() 
     58 
     59        # convert all links to relative and  
     60        # make them work without virtual hosting 
    14461        for url in urls: 
    14562            url = str(url) 
    146             image_id = url.rsplit('/', 1)[-1] 
    14763            # skip links with illegal url schema 
    14864            if '://' in url and not url.startswith('http://'): 
    14965                continue 
    150             # convert all all links to relative 
    15166            if url.startswith('http://'): 
    152                 for site in SITE_URLS: 
    153                     if url.startswith(site): 
     67                for domain in self.site_domains: 
     68                    if url.startswith(domain): 
    15469                        # check whether image is stored in blog 
    155                         relative_url = url[len(site):] 
     70                        relative_url = url[len(domain):] 
    15671                        relative_url = relative_url.strip('/') 
    15772                        # if link is broken we'll get an AttributeError 
     
    16075                        except AttributeError: 
    16176                            break 
    162                         in_blog = recurseToInterface(image, IBlog) is not None and True or False 
    163                         if in_blog: 
    164                             image_id = self.fixImageId(image, image_id, blog_path) 
    165                             level = len(context_path) - len(blog_path) - 1 
    166                             new_url = '/'.join(['..' for i in range(level)]) 
    167                             new_url = '/'.join((new_url, IMAGE_FOLDER, image_id)) 
    168                             text = text.replace(url, new_url, 1) 
    169                         else: 
    170                             # find how many levels self.context is under portal root 
    171                             level = len(context_path) - 3 
    172                             new_url = '/'.join(['..' for i in range(level)]) 
    173                             new_url  = new_url + '/' + relative_url 
    174                             text = text.replace(url, new_url, 1) 
     77                        level = len(context_path) - 3 
     78                        new_url = '/'.join(['..' for i in range(level)]) 
     79                        new_url  = new_url + '/' + relative_url 
     80                        text = text.replace(url, new_url, 1) 
    17581                        break 
    17682            else: 
     83                # if link is broken we'll get an AttributeError 
    17784                if url.startswith('/'): 
    178                     # if link is broken we'll get an AttributeError 
    17985                    try: 
    18086                        image = self.portal.unrestrictedTraverse(url.strip('/')) 
     
    18288                        continue 
    18389                else: 
    184                     # if link is broken we'll get an AttributeError 
    18590                    try: 
    18691                        image = self.context.unrestrictedTraverse(url) 
    18792                    except AttributeError: 
    18893                        continue 
    189                 in_blog = recurseToInterface(image, IBlog) is not None and True or False 
    190                 if in_blog: 
    191                     image_id = self.fixImageId(image, image_id, blog_path) 
    192                     level = len(context_path) - len(blog_path) - 1 
    193                     new_url = '/'.join(['..' for i in range(level)]) 
    194                     new_url = '/'.join([new_url, IMAGE_FOLDER, image_id]) 
    195                     text = text.replace(url, new_url, 1) 
    196                 elif url.startswith('../'): 
     94 
     95                if url.startswith('../'): 
     96                    # BlogEntry is folderish object and links to images that 
     97                    # are is the same folder as BlogEntry starts with '..' 
    19798                    # remove '../' from the start of string 
    19899                    new_url = url[3:] 
     
    209110        data['data'] = doc.toxml('utf-8') 
    210111        return data 
    211  
    212     def fixImageId(self, image, image_id, blog_path): 
    213         """ Check whether image is good or generate new if it's bad. 
    214         """ 
    215         image_path = '/'.join(image.getPhysicalPath()) 
    216         if image_id in IMAGE_IDS and image_path not in IMAGE_PATHS: 
    217             image_id = getUniqueId(image_id) 
    218         if image_id not in IMAGE_IDS: 
    219             IMAGE_IDS.append(image_id) 
    220             IMAGE_PATHS[image_path] = '/'.join(blog_path[2:] + (IMAGE_FOLDER, image_id)) 
    221  
    222         return image_id 
    223  
    224 class PathRewriter(object): 
    225     implements(IExportItemManipulator) 
    226  
    227     def __init__(self, context): 
    228         self.context = context 
    229  
    230     def __call__(self, item, **kw): 
    231         pathkey = kw.get('path') 
    232         if pathkey is None: 
    233             return item 
    234  
    235         path = item[pathkey] 
    236         blog = recurseToInterface(self.context, IBlog) 
    237         if blog is None: 
    238             return item 
    239  
    240         blog_path = blog.getPhysicalPath() 
    241         full_path = '/'.join(self.context.getPhysicalPath()) 
    242         image_id = path.rsplit('/', 1)[-1] 
    243         modified = False 
    244  
    245         if full_path in IMAGE_PATHS: 
    246             new_path = IMAGE_PATHS[full_path] 
    247         else: 
    248             unique_id = getUniqueId(image_id) 
    249             modified = image_id != unique_id 
    250             new_path = '/'.join(blog_path[2:] + (IMAGE_FOLDER, unique_id)) 
    251  
    252             IMAGE_IDS.append(image_id) 
    253             IMAGE_PATHS[full_path] = new_path 
    254  
    255         # change item's path 
    256         item[pathkey] = new_path 
    257         item['_oldpath'] = path 
    258  
    259         # now we need to fix object id in .marshall.xml 
    260         if modified: 
    261             if '_files' in item and 'marshall' in item['_files']: 
    262                 doc = minidom.parseString(item['_files']['marshall']['data']) 
    263                 elem = [i for i in doc.getElementsByTagName('field') if i.getAttribute('name') == 'id'][0] 
    264                 elem.firstChild.nodeValue = '\n\t\t%s\n\t' % unique_id 
    265                 item['_files']['marshall']['data'] = doc.toxml('utf-8') 
    266  
    267         return item 
    268  
    269 class ImageFolderSection(object): 
    270     """ This section will generate manifest files for image folders in blog. 
    271     """ 
    272     classProvides(ISectionBlueprint) 
    273     implements(ISection) 
    274  
    275     def __init__(self, transmogrifier, name, options, previous): 
    276         self.previous = previous 
    277         self.transmogrifier = transmogrifier 
    278  
    279         self.flagkey = defaultMatcher(options, 'old-path-key', name, 'oldpath') 
    280         self.typekey = defaultMatcher(options, 'type-key', name, 'type') 
    281         self.pathkey = defaultMatcher(options, 'path-key', name, 'path') 
    282  
    283  
    284         site_urls = options.get('site-urls', '') 
    285         site_urls = filter(None, [i.strip() for i in site_urls.splitlines()]) 
    286         for i in site_urls: 
    287             SITE_URLS.append(i) 
    288  
    289         self.anno = IAnnotations(transmogrifier) 
    290  
    291     def __iter__(self): 
    292         folders = {} 
    293  
    294         # safely get logging storage 
    295         if VALIDATIONKEY in self.anno: 
    296             log_storage = self.anno[VALIDATIONKEY] 
    297         else: 
    298             log_storage = None 
    299  
    300         for item in self.previous: 
    301             item_keys = item.keys() 
    302             pathkey = self.pathkey(*item_keys)[0] 
    303             typekey = self.typekey(*item_keys)[0] 
    304             oldpathkey = self.flagkey(*item_keys)[0] 
    305  
    306             # collect data about images moved to folders 
    307             if pathkey and typekey and oldpathkey: 
    308                 path = item[pathkey] 
    309                 old_path = item[oldpathkey] 
    310                 type_ = item[typekey] 
    311                 folder_path, image_id = path.rsplit('/', 1) 
    312                 folders.setdefault(folder_path, []).append((image_id, type_)) 
    313  
    314                 # update logging data (path) for this item 
    315                 if log_storage and log_storage[-1] == old_path: 
    316                     log_storage.pop() 
    317                     log_storage.append(path) 
    318  
    319             yield item 
    320  
    321         # generate manifests for those image folders 
    322         items = [] 
    323         for folder, entries in folders.items(): 
    324             items.append({'_entries': entries, pathkey: folder}) 
    325         exporter = ManifestExporterSection(self.transmogrifier, 'manifest', {'blueprint': 'manifest'}, iter(items)) 
    326         for item in exporter: 
    327             yield item 
    328  
    329         # clean registries 
    330         while IMAGE_IDS: IMAGE_IDS.pop() 
    331         while SITE_URLS: SITE_URLS.pop() 
    332         IMAGE_PATHS.clear() 
    333112 
    334113class WorkflowImporter(object): 
     
    352131        if workflow_id == 'simple_publication_workflow': 
    353132            return data 
     133 
    354134        wh.setAttribute('id', 'simple_publication_workflow') 
    355135        if workflow_id == 'simpleblog_workflow': 
  • quintagroup.transmogrifier.simpleblog2quills/branches/without_image_move/quintagroup/transmogrifier/simpleblog2quills/configure.zcml

    r612 r1247  
    99    <include package="quintagroup.transmogrifier" file="meta.zcml" /> 
    1010 
     11    <!-- this section is similar to datacorrector but has more power  
     12         to change pipeline item --> 
    1113    <utility 
    1214        component=".itemmanipulator.ItemManipulatorSection" 
     
    1618 
    1719    <configure zcml:condition="installed Products.SimpleBlog"> 
    18  
    19         <utility 
    20             component=".adapters.ImageFolderSection" 
    21             name="quintagroup.transmogrifier.simpleblog2quills.imagefolder" 
    22             provides="collective.transmogrifier.interfaces.ISectionBlueprint" 
    23             /> 
    2420 
    2521        <!-- In Plone 2.1 overrides.zcml isn't loaded, but conflicting configuration 
     
    3632 
    3733        <five:implements 
    38             class="Products.SimpleBlog.content.Blog" 
    39             interface=".interfaces.IBlog" 
    40             /> 
    41  
    42         <five:implements 
    43             class="Products.SimpleBlog.content.BlogFolder" 
    44             interface=".interfaces.IBlogFolder" 
    45             /> 
    46  
    47         <five:implements 
    4834            class="Products.SimpleBlog.content.BlogEntry" 
    4935            interface=".interfaces.IBlogEntry" 
    5036            /> 
    5137 
    52         <five:implements 
    53             class="Products.ATContentTypes.content.file.ATFile" 
    54             interface="quintagroup.transmogrifier.interfaces.IATFile" 
    55             /> 
    56  
    57         <five:implements 
    58             class="Products.ATContentTypes.content.image.ATImage" 
    59             interface="quintagroup.transmogrifier.interfaces.IATImage" 
    60             /> 
    61  
    62         <!-- 'datacorrector' section adapters --> 
    63         <adapter 
    64             for=".interfaces.IBlog" 
    65             provides="quintagroup.transmogrifier.interfaces.IExportDataCorrector" 
    66             factory=".adapters.BlogManifest" 
    67             name="manifest" 
    68             /> 
    69  
    70         <adapter 
    71             for=".interfaces.IBlogFolder" 
    72             provides="quintagroup.transmogrifier.interfaces.IExportDataCorrector" 
    73             factory=".adapters.BlogFolderManifest" 
    74             name="manifest" 
    75             /> 
    76  
     38        <!-- 'datacorrector' section adapter --> 
    7739        <adapter 
    7840            for=".interfaces.IBlogEntry" 
     
    8749            provides=".interfaces.IExportItemManipulator" 
    8850            factory=".adapters.BlogEntryManifest" 
    89             /> 
    90  
    91         <adapter 
    92             for="quintagroup.transmogrifier.interfaces.IATFile" 
    93             provides=".interfaces.IExportItemManipulator" 
    94             factory=".adapters.PathRewriter" 
    95             /> 
    96  
    97         <adapter 
    98             for="quintagroup.transmogrifier.interfaces.IATImage" 
    99             provides=".interfaces.IExportItemManipulator" 
    100             factory=".adapters.PathRewriter" 
    10151            /> 
    10252 
  • quintagroup.transmogrifier.simpleblog2quills/branches/without_image_move/quintagroup/transmogrifier/simpleblog2quills/export.cfg

    r1218 r1247  
    1010    datacorrector 
    1111    itemmanipulator 
    12     imagefolder 
    1312    writer 
    1413    EXPORTING 
     
    1615[sitewalker] 
    1716blueprint = quintagroup.transmogrifier.sitewalker 
    18 excluded-types = 
    19     ATAudio 
    20     TrackBack 
    2117 
    2218[condition] 
     
    4339blueprint = quintagroup.transmogrifier.datacorrector 
    4440sources = 
    45     manifest 
    4641    marshall 
    4742 
     
    4944blueprint = quintagroup.transmogrifier.itemmanipulator 
    5045type = export 
    51  
    52 # in this section you must write you site URL 
    53 [imagefolder] 
    54 blueprint = quintagroup.transmogrifier.simpleblog2quills.imagefolder 
    55 site-urls = 
    5646 
    5747[writer] 
  • quintagroup.transmogrifier.simpleblog2quills/branches/without_image_move/quintagroup/transmogrifier/simpleblog2quills/interfaces.py

    r612 r1247  
    11from zope.interface import Interface 
    2  
    3 class IBlog(Interface): 
    4     """ Marker interface for SimpleBlog blog object. 
    5     """ 
    6  
    7 class IBlogFolder(Interface): 
    8     """ Marker interface for SimpleBlog blog folder object. 
    9     """ 
    102 
    113class IBlogEntry(Interface): 
Note: See TracChangeset for help on using the changeset viewer.