SlideShare ist ein Scribd-Unternehmen logo
1 von 37
Downloaden Sie, um offline zu lesen
Migrating From Drupal
    to Plone with
    Transmogrifier
   Clayton Parker, Senior Developer
       PLONE SYMPOSIUM EAST 2011
Who Am I?                 PLONE SYMPOSIUM EAST 2011




• claytron
• Python dev since 2003
• Plone Core Committer
• Foundation Member
What will we learn?            PLONE SYMPOSIUM EAST 2011




• Transmogrifier basics
• Migration Planning Process
• Creating a pipeline
Migrations                    PLONE SYMPOSIUM EAST 2011




• One off scripts
• In multiple places
• Little to no re-usability
Transmogrifier                  PLONE SYMPOSIUM EAST 2011




• A framework for migrations
• Re-usable parts
Basics         PLONE SYMPOSIUM EAST 2011




• Pipeline
• Blueprints
• Sources
• Section
Sources                         PLONE SYMPOSIUM EAST 2011




• A blueprint
• First item in your pipeline
Example Pipeline                                PLONE SYMPOSIUM EAST 2011




 [transmogrifier]
 pipeline =
     csv_file
     constructor
     schemaupdater
        <html>
        <body>
 [csv_file]
        <h3>Code Sample</h3>
 blueprint = collective.transmogrifier.sections.csvsource
        <p>Replace this text!</p>
 filename = my.migration.import:my_items.csv
        </body>
        </html>
 [constructor]
 blueprint = collective.transmogrifier.sections.constructor

 [schemaupdater]
 blueprint = plone.app.transmogrifier.atschemaupdater
my_items.csv                                                 PLONE SYMPOSIUM EAST 2011




_path          ,   _type      ,   title           ,   description
/folder1       ,   Folder     ,   First Folder    ,   This is folder One
/folder2       ,   Folder     ,   Second Folder   ,   This is folder Two
/folder1/foo   ,   Document   ,   One Foo         ,   A document named foo
/folder2/foo   ,   Document   ,   Two Foo         ,   Another doc named foo
The Result   PLONE SYMPOSIUM EAST 2011
Items                                    PLONE SYMPOSIUM EAST 2011




• Each item is a mapping
• Keys are fields
• Keys with a leading underscore are controllers
Example Item                                       PLONE SYMPOSIUM EAST 2011




{'_id': 'a-stronger-connection-to-out-customers',
 '_path': 'content/stronger-connection-out-customers',
 '_status': 1L,
 '_text_mimetype': 'text/html',
 '_transitions': 'publish',
 '_type': 'Document',
 'allowDiscussion': False,
 'creation_date': '2011/05/14 9:20:50',
 'effectiveDate': '2011/05/14 9:20:50',
 'modification_date': '2011/05/18 9:22:22',
 'subject': 'betterninterestingnstronger',
 'text': '<p>this is some text</p>rn',
 'title': 'A stronger connection to out customers'}
Migration Strategy                PLONE SYMPOSIUM EAST 2011




• Investigate the source
• Prepare the destination
• Find Transmogrifier blueprints
• Write the pipeline
Write your own         PLONE SYMPOSIUM EAST 2011




• Missing blueprint
• Write one
• Contribute it back
GenericSetup                            PLONE SYMPOSIUM EAST 2011




• Make migration part of your release
• Ability to package migrations
My Migration                PLONE SYMPOSIUM EAST 2011




• Drupal backed by MySQL
• transmogrify.sqlalchemy
• Plone 4.0.5
• collective.blog.star
• plone.app.discussion
Package Layout                               PLONE SYMPOSIUM EAST 2011


    my.migration
    !"" my
    #   !"" __init__.py
    #   %"" migration
    #       !"" __init__.py
    #       !"" config
    #       #   !"" articles.cfg
    #       #   !"" base.cfg
    #       #   !"" blogs.cfg
    #       #   !"" comments.cfg
    #       #   %"" pages.cfg
    #       !"" configure.zcml
    #       %"" profiles
    #           %"" default
    #               !"" metadata.xml
    #               %"" transmogrifier.txt
    !"" setup.cfg
    %"" setup.py
Registering Configs                               PLONE SYMPOSIUM EAST 2011




<transmogrifier:registerConfig
    name="my.migration.base"
    title="My migration base config"
    description="Base settings for all transmogrifier imports"
    configuration="config/base.cfg"
    />
Registering Configs                               PLONE SYMPOSIUM EAST 2011




<transmogrifier:registerConfig
    name="my.migration.pages"
    title="Drupal pages"
    description="Import pages from Drupal into Plone"
    configuration="config/pages.cfg"
    />
Registering Configs                               PLONE SYMPOSIUM EAST 2011




<transmogrifier:registerConfig
    name="my.migration.articles"
    title="Drupal articles"
    description="Import articles from Drupal into Plone"
    configuration="config/articles.cfg"
    />
Registering Configs                               PLONE SYMPOSIUM EAST 2011




<transmogrifier:registerConfig
    name="my.migration.blogs"
    title="Drupal blog entries"
    description="Import blog entries from Drupal into Plone"
    configuration="config/blogs.cfg"
    />
Registering Configs                               PLONE SYMPOSIUM EAST 2011




<transmogrifier:registerConfig
    name="my.migration.comments"
    title="Drupal comments"
    description="Import comments from Drupal into Plone"
    configuration="config/comments.cfg"
    />
transmogrifier.txt           PLONE SYMPOSIUM EAST 2011




    my.migration.pages
    my.migration.articles
    my.migration.blogs
    my.migration.comments
Package Layout                               PLONE SYMPOSIUM EAST 2011


    my.migration
    !"" my
    #   !"" __init__.py
    #   %"" migration
    #       !"" __init__.py
    #       !"" config
    #       #   !"" articles.cfg
    #       #   !"" base.cfg
    #       #   !"" blogs.cfg
    #       #   !"" comments.cfg
    #       #   %"" pages.cfg
    #       !"" configure.zcml
    #       %"" profiles
    #           %"" default
    #               !"" metadata.xml
    #               %"" transmogrifier.txt
    !"" setup.cfg
    %"" setup.py
base.cfg pipeline                                   PLONE SYMPOSIUM EAST 2011


    [transmogrifier]
    pipeline =
        drupal
        portal_type
        url_normalizer
        path
        publication_state
        text_mimetype
        mimetype_encapsulator
        folders
        constructor
        commenting
        comments
        schema_update
        workflow
        reindex_object

    [settings]
    # Path to use if there isn’t one given
    base_path = other-content
    # Have to escape python string formatting for when
    # this gets passed into sqlalchemy
    date_format = %%Y/%%m/%%d %%k:%%i:%%s
drupal section                                 PLONE SYMPOSIUM EAST 2011




  [drupal]
  blueprint = transmogrify.sqlalchemy
  dsn = mysql://user:password@localhost/drupal-transmog
articles.cfg                                                                PLONE SYMPOSIUM EAST 2011



 [transmogrifier]
 include = my.migration.base

 [drupal]
 query =
 	 SELECT
 	 	 node.title,
 	 	 node.status AS status,
 	 	 GROUP_CONCAT(tag_data.name SEPARATOR 'n') AS subject,
 	 	 FROM_UNIXTIME(node.created, "${settings:date_format}") AS creation_date,
 	 	 FROM_UNIXTIME(node.created, "${settings:date_format}") AS effectiveDate,
 	 	 FROM_UNIXTIME(node.changed, "${settings:date_format}") AS modification_date,
 	 	 body_data.body_value AS text
 	 	 url_alias.alias AS _path
 	 FROM node
       INNER JOIN field_data_field_tags AS tag_field ON tag_field.entity_id = node.nid
       INNER JOIN taxonomy_term_data AS tag_data ON tag_data.tid = tag_field.field_tags_tid
       INNER JOIN field_data_body AS body_data ON body_data.entity_id = node.nid
       INNER JOIN url_alias ON url_alias.source = CONCAT("node/", node.nid)
 	 GROUP BY
 	 	 node.title,
 	 	 node.status,
 	 	 node.created,
 	 	 node.changed,
 	 	 body_data.body_value,
 	 	 url_alias.alias;

 [portal_type]
 value = string:Document
pages.cfg                                                                   PLONE SYMPOSIUM EAST 2011



  [transmogrifier]
  include = my.migration.base

  [drupal]
  query =
  	 my.migration.base
  	 SELECT
  	 	     node.title,
           node.status AS _status,
           FROM_UNIXTIME(node.created, "${settings:date_format}") AS creation_date,
           FROM_UNIXTIME(node.created, "${settings:date_format}") AS effectiveDate,
           FROM_UNIXTIME(node.changed, "${settings:date_format}") AS modification_date,
  	 	     body_data.body_value AS text,
  	 	     url_alias.alias AS _path
  	 FROM node
           INNER JOIN field_data_body AS body_data ON body_data.entity_id = node.nid
           INNER JOIN url_alias ON url_alias.source = CONCAT("node/", node.nid)
      WHERE node.type = "page"
  	 GROUP BY
  	       node.title,
  	 	     node.status,
  	 	     node.created,
  	 	     node.changed,
  	 	     body_data.body_value,
  	 	     url_alias.alias;	 	

  [portal_type]
  value = string:Document
blogs.cfg                                                                   PLONE SYMPOSIUM EAST 2011


  [transmogrifier]
  include = my.migration.base

  [drupal]
  query =
      SELECT
           node.title,
           node.satus AS _status,
           FROM_UNIXTIME(node.created, "${settings:date_format}") AS creation_date,
           FROM_UNIXTIME(node.created, "${settings:date_format}") AS effectiveDate,
           FROM_UNIXTIME(node.created, "${settings:date_format}") AS modification_date,
           body_data.body_value AS text,
           url_alias.alias AS _path
      FROM node
           INNER JOIN field_data_body AS body_data ON body_data.entity_id = node.nid
           INNER JOIN url_alias ON url_alias.source = CONCAT("node/", node.nid)
      WHERE node.type = "blog"
      GROUP BY
           node.title,
           node.status,
           node.created,
           node.changed,
           body_data.body_value,
           url_alias.alias;

  [portal_type]
  value = string:BlogEntry

  [commenting]
  value = python:True
comments.cfg                                                               PLONE SYMPOSIUM EAST 2011


 [transmogrifier]
 include = my.migration.base

 [drupal]
 query =
     my.migration.base
     SELECT
          comment.subject AS title,
          FROM_UNIXTIME(comment.created, "${settings:date_format}") AS published,
          FROM_UNIXTIME(comment.changed, "${settings:date_format}") AS updated,
          comment.name AS author_name,
          body_data.comment_body_value AS text,
          url_alias.alias AS _parent_path
     FROM comment
          INNER JOIN field_data_comment_body AS body_data ON body_data.entity_id =
 comment.cid
          INNER JOIN node ON node.nid = comment.nid
          INNER JOIN url_alias ON url_alias.source = CONCAT("node/", node.nid)
     GROUP BY
          comment.subject,
          comment.created,
          comment.changed,
          comment.name,
          body_data.comment_body_value,
          url_alias.alias;

 [portal_type]
 # Override the portal type to use the "comment_type"
 key = string:_comment_type
 value = string:plone.app.discussion
base.cfg overrides                                         PLONE SYMPOSIUM EAST 2011




 [path]
 blueprint = collective.transmogrifier.sections.inserter
 # only add a path if one does not exist
 condition = python:'_path' not in item and not '_parent_path' in item
 key = string:_path
 # Add the value in the extended configuration
 value = string:${settings:base_path}/${item/_id}

 [portal_type]
 blueprint = collective.transmogrifier.sections.inserter
 key = string:_type
 # We will add the value in the extended config, but we need a
 # default set here
 value = string:

 [commenting]
 blueprint = collective.transmogrifier.sections.inserter
 key = string:allowDiscussion
 # default to false
 value = python:False
Content Creation                                          PLONE SYMPOSIUM EAST 2011




 [comments]
 blueprint = transmogrify.comments

 [folders]
 blueprint = collective.transmogrifier.sections.folders

 [constructor]
 blueprint = collective.transmogrifier.sections.constructor

 [schema_update]
 blueprint = plone.app.transmogrifier.atschemaupdater

 [workflow]
 blueprint = plone.app.transmogrifier.workflowupdater

 [reindex_object]
 blueprint = plone.app.transmogrifier.reindexobject
Item Modification                                         PLONE SYMPOSIUM EAST 2011




 [publication_state]
 blueprint = collective.transmogrifier.sections.inserter
 condition = python:'_status' in item and item['_status'] == 1
 key = string:_transitions
 value = string:publish

 [text_mimetype]
 # This could probably be taken from the database as well
 blueprint = collective.transmogrifier.sections.inserter
 key = string:_text_mimetype
 value = string:text/html

 [mimetype_encapsulator]
 blueprint = plone.app.transmogrifier.mimeencapsulator
 key = text
 mimetype = python:item.get('_%s_mimetype', key)
 field = key
 condition = mimetype
PLONE SYMPOSIUM EAST 2011




DEMO
Links                                              PLONE SYMPOSIUM EAST 2011




• collective.transmogrifier
http://pypi.python.org/pypi/collective.transmogrifier/

• plone.app.transmogrifier
http://pypi.python.org/pypi/plone.app.transmogrifier/
Useful Sources and            PLONE SYMPOSIUM EAST 2011



Blueprints
• plone.app.transmogrifier
• transmogrify.filesystem
• transmogrify.sqlalchemy
• transmogrify.webcrawler
• quintagroup.transmogrifier
• transmogrify.comments
Check out
          .co m/d emos
s ixfeetup

Weitere ähnliche Inhalte

Was ist angesagt?

What's new in PHP 5.5
What's new in PHP 5.5What's new in PHP 5.5
What's new in PHP 5.5
Tom Corrigan
 
Introducing PHP Latest Updates
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest Updates
Iftekhar Eather
 
Node.js basics
Node.js basicsNode.js basics
Node.js basics
Ben Lin
 

Was ist angesagt? (20)

Beauty and Power of Go
Beauty and Power of GoBeauty and Power of Go
Beauty and Power of Go
 
What's new in PHP 5.5
What's new in PHP 5.5What's new in PHP 5.5
What's new in PHP 5.5
 
PHP7 Presentation
PHP7 PresentationPHP7 Presentation
PHP7 Presentation
 
7 Common mistakes in Go and when to avoid them
7 Common mistakes in Go and when to avoid them7 Common mistakes in Go and when to avoid them
7 Common mistakes in Go and when to avoid them
 
A new way to develop with WordPress!
A new way to develop with WordPress!A new way to develop with WordPress!
A new way to develop with WordPress!
 
The new features of PHP 7
The new features of PHP 7The new features of PHP 7
The new features of PHP 7
 
Introducing PHP Latest Updates
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest Updates
 
Something about Golang
Something about GolangSomething about Golang
Something about Golang
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring Clojurescript
 
Node.js basics
Node.js basicsNode.js basics
Node.js basics
 
New Design of OneRing
New Design of OneRingNew Design of OneRing
New Design of OneRing
 
Testing con spock
Testing con spockTesting con spock
Testing con spock
 
The GO Language : From Beginners to Gophers
The GO Language : From Beginners to GophersThe GO Language : From Beginners to Gophers
The GO Language : From Beginners to Gophers
 
Groovy & Grails: Scripting for Modern Web Applications
Groovy & Grails: Scripting for Modern Web ApplicationsGroovy & Grails: Scripting for Modern Web Applications
Groovy & Grails: Scripting for Modern Web Applications
 
Txjs
TxjsTxjs
Txjs
 
Concurrency in go
Concurrency in goConcurrency in go
Concurrency in go
 
RDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по DipRDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по Dip
 
How to Scrap Any Website's content using ScrapyTutorial of How to scrape (cra...
How to Scrap Any Website's content using ScrapyTutorial of How to scrape (cra...How to Scrap Any Website's content using ScrapyTutorial of How to scrape (cra...
How to Scrap Any Website's content using ScrapyTutorial of How to scrape (cra...
 
groovy & grails - lecture 4
groovy & grails - lecture 4groovy & grails - lecture 4
groovy & grails - lecture 4
 
Web Crawling with NodeJS
Web Crawling with NodeJSWeb Crawling with NodeJS
Web Crawling with NodeJS
 

Ähnlich wie Migrating from drupal to plone with transmogrifier

GDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App EngineGDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App Engine
Yared Ayalew
 
Frameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHPFrameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHP
Dan Jesus
 
An Introduction to Tornado
An Introduction to TornadoAn Introduction to Tornado
An Introduction to Tornado
Gavin Roy
 

Ähnlich wie Migrating from drupal to plone with transmogrifier (20)

Pyramid Lighter/Faster/Better web apps
Pyramid Lighter/Faster/Better web appsPyramid Lighter/Faster/Better web apps
Pyramid Lighter/Faster/Better web apps
 
Mojolicious - A new hope
Mojolicious - A new hopeMojolicious - A new hope
Mojolicious - A new hope
 
Python Code Camp for Professionals 3/4
Python Code Camp for Professionals 3/4Python Code Camp for Professionals 3/4
Python Code Camp for Professionals 3/4
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
 
Symfony2 revealed
Symfony2 revealedSymfony2 revealed
Symfony2 revealed
 
PhpBB meets Symfony2
PhpBB meets Symfony2PhpBB meets Symfony2
PhpBB meets Symfony2
 
Drupal 8 Configuration Management
Drupal 8 Configuration ManagementDrupal 8 Configuration Management
Drupal 8 Configuration Management
 
WordPress as the Backbone(.js)
WordPress as the Backbone(.js)WordPress as the Backbone(.js)
WordPress as the Backbone(.js)
 
GDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App EngineGDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App Engine
 
Flask intro - ROSEdu web workshops
Flask intro - ROSEdu web workshopsFlask intro - ROSEdu web workshops
Flask intro - ROSEdu web workshops
 
Building Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSBuilding Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJS
 
Frameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHPFrameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHP
 
An Introduction to Tornado
An Introduction to TornadoAn Introduction to Tornado
An Introduction to Tornado
 
Python Code Camp for Professionals 1/4
Python Code Camp for Professionals 1/4Python Code Camp for Professionals 1/4
Python Code Camp for Professionals 1/4
 
Flask – Python
Flask – PythonFlask – Python
Flask – Python
 
Building a real life application in node js
Building a real life application in node jsBuilding a real life application in node js
Building a real life application in node js
 
TYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase frameworkTYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase framework
 
Twas the night before Malware...
Twas the night before Malware...Twas the night before Malware...
Twas the night before Malware...
 
Drupal 8 configuration management
Drupal 8 configuration managementDrupal 8 configuration management
Drupal 8 configuration management
 
Angular JS2 Training Session #2
Angular JS2 Training Session #2Angular JS2 Training Session #2
Angular JS2 Training Session #2
 

Mehr von Clayton Parker

Pioneer a Strategic Change in Content Organization with Plone
Pioneer a Strategic Change in Content Organization with PlonePioneer a Strategic Change in Content Organization with Plone
Pioneer a Strategic Change in Content Organization with Plone
Clayton Parker
 

Mehr von Clayton Parker (20)

Customizing Your Shell With Dotfiles
Customizing Your Shell With DotfilesCustomizing Your Shell With Dotfiles
Customizing Your Shell With Dotfiles
 
Vim for Mere Mortals
Vim for Mere MortalsVim for Mere Mortals
Vim for Mere Mortals
 
Fuzzy Feelings for Fuzzy Matching
Fuzzy Feelings for Fuzzy MatchingFuzzy Feelings for Fuzzy Matching
Fuzzy Feelings for Fuzzy Matching
 
Exploring Code with Pry!
Exploring Code with Pry!Exploring Code with Pry!
Exploring Code with Pry!
 
Zen and the Art of Python
Zen and the Art of PythonZen and the Art of Python
Zen and the Art of Python
 
So you think you can pdb?
So you think you can pdb?So you think you can pdb?
So you think you can pdb?
 
Managing Chaos: Merging 120 Sites into a single Plone Multisite Solution
Managing Chaos: Merging 120 Sites into a single Plone Multisite SolutionManaging Chaos: Merging 120 Sites into a single Plone Multisite Solution
Managing Chaos: Merging 120 Sites into a single Plone Multisite Solution
 
Current State of Python Packaging
Current State of Python PackagingCurrent State of Python Packaging
Current State of Python Packaging
 
Notre Dame Seamless Syndication with Lineage
Notre Dame Seamless Syndication with LineageNotre Dame Seamless Syndication with Lineage
Notre Dame Seamless Syndication with Lineage
 
Pioneer a Strategic Change in Content Organization with Plone
Pioneer a Strategic Change in Content Organization with PlonePioneer a Strategic Change in Content Organization with Plone
Pioneer a Strategic Change in Content Organization with Plone
 
Using Buildout, GenericSetup and a Policy Package to Rule the World
Using Buildout, GenericSetup and a Policy Package to Rule the WorldUsing Buildout, GenericSetup and a Policy Package to Rule the World
Using Buildout, GenericSetup and a Policy Package to Rule the World
 
Make Plone Search Act Like Google Using Solr
Make Plone Search Act Like Google Using SolrMake Plone Search Act Like Google Using Solr
Make Plone Search Act Like Google Using Solr
 
Buildout for the Future
Buildout for the FutureBuildout for the Future
Buildout for the Future
 
Buildout future
Buildout futureBuildout future
Buildout future
 
LDAP and Active Directory Authentication in Plone
LDAP and Active Directory Authentication in PloneLDAP and Active Directory Authentication in Plone
LDAP and Active Directory Authentication in Plone
 
Code with Style - PyOhio
Code with Style - PyOhioCode with Style - PyOhio
Code with Style - PyOhio
 
Code with style
Code with styleCode with style
Code with style
 
Using Buildout to Develop and Deploy Python Projects
Using Buildout to Develop and Deploy Python ProjectsUsing Buildout to Develop and Deploy Python Projects
Using Buildout to Develop and Deploy Python Projects
 
Generic Setup De-Mystified
Generic Setup De-MystifiedGeneric Setup De-Mystified
Generic Setup De-Mystified
 
Buildout: Fostering Repeatability
Buildout: Fostering RepeatabilityBuildout: Fostering Repeatability
Buildout: Fostering Repeatability
 

Kürzlich hochgeladen

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Kürzlich hochgeladen (20)

Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 

Migrating from drupal to plone with transmogrifier

  • 1. Migrating From Drupal to Plone with Transmogrifier Clayton Parker, Senior Developer PLONE SYMPOSIUM EAST 2011
  • 2. Who Am I? PLONE SYMPOSIUM EAST 2011 • claytron • Python dev since 2003 • Plone Core Committer • Foundation Member
  • 3. What will we learn? PLONE SYMPOSIUM EAST 2011 • Transmogrifier basics • Migration Planning Process • Creating a pipeline
  • 4. Migrations PLONE SYMPOSIUM EAST 2011 • One off scripts • In multiple places • Little to no re-usability
  • 5. Transmogrifier PLONE SYMPOSIUM EAST 2011 • A framework for migrations • Re-usable parts
  • 6. Basics PLONE SYMPOSIUM EAST 2011 • Pipeline • Blueprints • Sources • Section
  • 7. Sources PLONE SYMPOSIUM EAST 2011 • A blueprint • First item in your pipeline
  • 8. Example Pipeline PLONE SYMPOSIUM EAST 2011 [transmogrifier] pipeline = csv_file constructor schemaupdater <html> <body> [csv_file] <h3>Code Sample</h3> blueprint = collective.transmogrifier.sections.csvsource <p>Replace this text!</p> filename = my.migration.import:my_items.csv </body> </html> [constructor] blueprint = collective.transmogrifier.sections.constructor [schemaupdater] blueprint = plone.app.transmogrifier.atschemaupdater
  • 9. my_items.csv PLONE SYMPOSIUM EAST 2011 _path , _type , title , description /folder1 , Folder , First Folder , This is folder One /folder2 , Folder , Second Folder , This is folder Two /folder1/foo , Document , One Foo , A document named foo /folder2/foo , Document , Two Foo , Another doc named foo
  • 10. The Result PLONE SYMPOSIUM EAST 2011
  • 11. Items PLONE SYMPOSIUM EAST 2011 • Each item is a mapping • Keys are fields • Keys with a leading underscore are controllers
  • 12. Example Item PLONE SYMPOSIUM EAST 2011 {'_id': 'a-stronger-connection-to-out-customers', '_path': 'content/stronger-connection-out-customers', '_status': 1L, '_text_mimetype': 'text/html', '_transitions': 'publish', '_type': 'Document', 'allowDiscussion': False, 'creation_date': '2011/05/14 9:20:50', 'effectiveDate': '2011/05/14 9:20:50', 'modification_date': '2011/05/18 9:22:22', 'subject': 'betterninterestingnstronger', 'text': '<p>this is some text</p>rn', 'title': 'A stronger connection to out customers'}
  • 13. Migration Strategy PLONE SYMPOSIUM EAST 2011 • Investigate the source • Prepare the destination • Find Transmogrifier blueprints • Write the pipeline
  • 14. Write your own PLONE SYMPOSIUM EAST 2011 • Missing blueprint • Write one • Contribute it back
  • 15. GenericSetup PLONE SYMPOSIUM EAST 2011 • Make migration part of your release • Ability to package migrations
  • 16. My Migration PLONE SYMPOSIUM EAST 2011 • Drupal backed by MySQL • transmogrify.sqlalchemy • Plone 4.0.5 • collective.blog.star • plone.app.discussion
  • 17. Package Layout PLONE SYMPOSIUM EAST 2011 my.migration !"" my #   !"" __init__.py #   %"" migration #   !"" __init__.py #   !"" config #   #   !"" articles.cfg #   #   !"" base.cfg #   #   !"" blogs.cfg #   #   !"" comments.cfg #   #   %"" pages.cfg #   !"" configure.zcml #   %"" profiles #      %"" default #      !"" metadata.xml #      %"" transmogrifier.txt !"" setup.cfg %"" setup.py
  • 18. Registering Configs PLONE SYMPOSIUM EAST 2011 <transmogrifier:registerConfig name="my.migration.base" title="My migration base config" description="Base settings for all transmogrifier imports" configuration="config/base.cfg" />
  • 19. Registering Configs PLONE SYMPOSIUM EAST 2011 <transmogrifier:registerConfig name="my.migration.pages" title="Drupal pages" description="Import pages from Drupal into Plone" configuration="config/pages.cfg" />
  • 20. Registering Configs PLONE SYMPOSIUM EAST 2011 <transmogrifier:registerConfig name="my.migration.articles" title="Drupal articles" description="Import articles from Drupal into Plone" configuration="config/articles.cfg" />
  • 21. Registering Configs PLONE SYMPOSIUM EAST 2011 <transmogrifier:registerConfig name="my.migration.blogs" title="Drupal blog entries" description="Import blog entries from Drupal into Plone" configuration="config/blogs.cfg" />
  • 22. Registering Configs PLONE SYMPOSIUM EAST 2011 <transmogrifier:registerConfig name="my.migration.comments" title="Drupal comments" description="Import comments from Drupal into Plone" configuration="config/comments.cfg" />
  • 23. transmogrifier.txt PLONE SYMPOSIUM EAST 2011 my.migration.pages my.migration.articles my.migration.blogs my.migration.comments
  • 24. Package Layout PLONE SYMPOSIUM EAST 2011 my.migration !"" my #   !"" __init__.py #   %"" migration #   !"" __init__.py #   !"" config #   #   !"" articles.cfg #   #   !"" base.cfg #   #   !"" blogs.cfg #   #   !"" comments.cfg #   #   %"" pages.cfg #   !"" configure.zcml #   %"" profiles #      %"" default #      !"" metadata.xml #      %"" transmogrifier.txt !"" setup.cfg %"" setup.py
  • 25. base.cfg pipeline PLONE SYMPOSIUM EAST 2011 [transmogrifier] pipeline = drupal portal_type url_normalizer path publication_state text_mimetype mimetype_encapsulator folders constructor commenting comments schema_update workflow reindex_object [settings] # Path to use if there isn’t one given base_path = other-content # Have to escape python string formatting for when # this gets passed into sqlalchemy date_format = %%Y/%%m/%%d %%k:%%i:%%s
  • 26. drupal section PLONE SYMPOSIUM EAST 2011 [drupal] blueprint = transmogrify.sqlalchemy dsn = mysql://user:password@localhost/drupal-transmog
  • 27. articles.cfg PLONE SYMPOSIUM EAST 2011 [transmogrifier] include = my.migration.base [drupal] query = SELECT node.title, node.status AS status, GROUP_CONCAT(tag_data.name SEPARATOR 'n') AS subject, FROM_UNIXTIME(node.created, "${settings:date_format}") AS creation_date, FROM_UNIXTIME(node.created, "${settings:date_format}") AS effectiveDate, FROM_UNIXTIME(node.changed, "${settings:date_format}") AS modification_date, body_data.body_value AS text url_alias.alias AS _path FROM node INNER JOIN field_data_field_tags AS tag_field ON tag_field.entity_id = node.nid INNER JOIN taxonomy_term_data AS tag_data ON tag_data.tid = tag_field.field_tags_tid INNER JOIN field_data_body AS body_data ON body_data.entity_id = node.nid INNER JOIN url_alias ON url_alias.source = CONCAT("node/", node.nid) GROUP BY node.title, node.status, node.created, node.changed, body_data.body_value, url_alias.alias; [portal_type] value = string:Document
  • 28. pages.cfg PLONE SYMPOSIUM EAST 2011 [transmogrifier] include = my.migration.base [drupal] query = my.migration.base SELECT node.title, node.status AS _status, FROM_UNIXTIME(node.created, "${settings:date_format}") AS creation_date, FROM_UNIXTIME(node.created, "${settings:date_format}") AS effectiveDate, FROM_UNIXTIME(node.changed, "${settings:date_format}") AS modification_date, body_data.body_value AS text, url_alias.alias AS _path FROM node INNER JOIN field_data_body AS body_data ON body_data.entity_id = node.nid INNER JOIN url_alias ON url_alias.source = CONCAT("node/", node.nid) WHERE node.type = "page" GROUP BY node.title, node.status, node.created, node.changed, body_data.body_value, url_alias.alias; [portal_type] value = string:Document
  • 29. blogs.cfg PLONE SYMPOSIUM EAST 2011 [transmogrifier] include = my.migration.base [drupal] query = SELECT node.title, node.satus AS _status, FROM_UNIXTIME(node.created, "${settings:date_format}") AS creation_date, FROM_UNIXTIME(node.created, "${settings:date_format}") AS effectiveDate, FROM_UNIXTIME(node.created, "${settings:date_format}") AS modification_date, body_data.body_value AS text, url_alias.alias AS _path FROM node INNER JOIN field_data_body AS body_data ON body_data.entity_id = node.nid INNER JOIN url_alias ON url_alias.source = CONCAT("node/", node.nid) WHERE node.type = "blog" GROUP BY node.title, node.status, node.created, node.changed, body_data.body_value, url_alias.alias; [portal_type] value = string:BlogEntry [commenting] value = python:True
  • 30. comments.cfg PLONE SYMPOSIUM EAST 2011 [transmogrifier] include = my.migration.base [drupal] query = my.migration.base SELECT comment.subject AS title, FROM_UNIXTIME(comment.created, "${settings:date_format}") AS published, FROM_UNIXTIME(comment.changed, "${settings:date_format}") AS updated, comment.name AS author_name, body_data.comment_body_value AS text, url_alias.alias AS _parent_path FROM comment INNER JOIN field_data_comment_body AS body_data ON body_data.entity_id = comment.cid INNER JOIN node ON node.nid = comment.nid INNER JOIN url_alias ON url_alias.source = CONCAT("node/", node.nid) GROUP BY comment.subject, comment.created, comment.changed, comment.name, body_data.comment_body_value, url_alias.alias; [portal_type] # Override the portal type to use the "comment_type" key = string:_comment_type value = string:plone.app.discussion
  • 31. base.cfg overrides PLONE SYMPOSIUM EAST 2011 [path] blueprint = collective.transmogrifier.sections.inserter # only add a path if one does not exist condition = python:'_path' not in item and not '_parent_path' in item key = string:_path # Add the value in the extended configuration value = string:${settings:base_path}/${item/_id} [portal_type] blueprint = collective.transmogrifier.sections.inserter key = string:_type # We will add the value in the extended config, but we need a # default set here value = string: [commenting] blueprint = collective.transmogrifier.sections.inserter key = string:allowDiscussion # default to false value = python:False
  • 32. Content Creation PLONE SYMPOSIUM EAST 2011 [comments] blueprint = transmogrify.comments [folders] blueprint = collective.transmogrifier.sections.folders [constructor] blueprint = collective.transmogrifier.sections.constructor [schema_update] blueprint = plone.app.transmogrifier.atschemaupdater [workflow] blueprint = plone.app.transmogrifier.workflowupdater [reindex_object] blueprint = plone.app.transmogrifier.reindexobject
  • 33. Item Modification PLONE SYMPOSIUM EAST 2011 [publication_state] blueprint = collective.transmogrifier.sections.inserter condition = python:'_status' in item and item['_status'] == 1 key = string:_transitions value = string:publish [text_mimetype] # This could probably be taken from the database as well blueprint = collective.transmogrifier.sections.inserter key = string:_text_mimetype value = string:text/html [mimetype_encapsulator] blueprint = plone.app.transmogrifier.mimeencapsulator key = text mimetype = python:item.get('_%s_mimetype', key) field = key condition = mimetype
  • 34. PLONE SYMPOSIUM EAST 2011 DEMO
  • 35. Links PLONE SYMPOSIUM EAST 2011 • collective.transmogrifier http://pypi.python.org/pypi/collective.transmogrifier/ • plone.app.transmogrifier http://pypi.python.org/pypi/plone.app.transmogrifier/
  • 36. Useful Sources and PLONE SYMPOSIUM EAST 2011 Blueprints • plone.app.transmogrifier • transmogrify.filesystem • transmogrify.sqlalchemy • transmogrify.webcrawler • quintagroup.transmogrifier • transmogrify.comments
  • 37. Check out .co m/d emos s ixfeetup