dotclear vers typo

Mis à jour : 17.07.2007 par Jérôme Schell

Voici un script qui permet de migrer un blog de dotclear vers typo. Il devrait être placé dans le répertoire db/converters de typo.

Dans votre fichier /../../config/environment/database.yml vous devez spécifier votre base de données cible. Ce script est basé sur les scripts de conversion fournis avec typo, et est certainement améliorable. Il permet de changer de SGBD (mysql vers postgresql).


#!/usr/bin/env ruby

# Doctclear 1.x converter for typo by Frederic Logier
# Modified on Jul 2007 by Jerome Schell <jerome@myreseau.org> 
#
# MAKE BACKUPS OF EVERYTHING BEFORE RUNNING THIS SCRIPT!
# THIS SCRIPT IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND
# 
# Usage:
# - Put this script in db/converters of your Typo installation
# - Your config/database.yml must be properly configured and
#   your DB should be populated (use "rake db:migrate")
# - you can create your initial Typo user (to affect articles to him)  
# - cd into db/converters
# - launch the script this way:
#   $ RAILS_ENV=production ruby ./dotclear.rb --db-source-type mysql \
#   --db-source-host localhost --db-source-name your_dotclear_db \
#   --db-source-username dotclear_user --db-source-password db_pass \
#   --author typo_user_login
#
# Note:
# - The script assume that your dotclear database is encoded in ISO-8859-1.
#   If this is not the case you should modify it (TODO: add a command line
#   switch).
# - All comments with status of unpublished will be mark as spam
# - Script tested with dotclear 1.2.x and Typo 4.1

require File.dirname(__FILE__) + '/../../config/environment'
require 'optparse'

class DCHandler < ActiveRecord::Base
  def self.setDB(opts)
    @@adapter = opts[:adapter]
    @@host = opts[:host]
    @@database = opts[:database]
    @@username = opts[:username]
    @@password = opts[:password]
    @@prefix = opts[:prefix]
    DCHandler::establish_connection(:adapter => @@adapter,
                         :host => @@host,
                         :database => @@database,
                         :username => @@username,
                         :password => @@password)
  end

  def self.getDCCategories
    connection.select_all(%{
        SELECT cat_libelle AS name
        FROM #{@@database}.#{@@prefix}_categorie
      })
  end

  def self.getDCEntries
    connection.select_all(%{
      SELECT
       post_id as id,
        1 AS allow_pings,
        post_titre AS title,
        post_open_comment AS allow_comments,
        post_chapo AS chapo,
    post_content AS body,
        post_creadt AS created_at,
        post_creadt AS published_at,
        user_id AS author,
        1 AS published,
       cat_id
      FROM #{@@database}.#{@@prefix}_post
    })
  end

  def self.getDCCategorie(cat_id)
    connection.select_all(%{
          SELECT cat_libelle
          FROM #{@@database}.#{@@prefix}_categorie
          WHERE cat_id = #{cat_id}
        })
  end

  def self.getDCEntryComments(entry_id)
    connection.select_all(%{
        SELECT
          comment_auteur AS author,
          comment_email AS email,
          comment_site AS url,
          comment_content AS body,
          comment_dt AS created_at,
          comment_ip AS ip,
      comment_pub AS published
        FROM #{@@database}.#{@@prefix}_comment
        WHERE post_id = #{entry_id}
      })
  end
end

class DCMigrate
  attr_accessor :options

  def initialize
    self.options = {}
    self.parse_options
    DCHandler::setDB(:adapter => self.options[:dc_db_type],
                  :host => self.options[:dc_db_host],
                     :database => self.options[:dc_db_name],
                     :username => self.options[:dc_db_username],
                     :password => self.options[:dc_db_password],
             :prefix => self.options[:dc_prefix]
            )

    self.convert_categories
    self.convert_entries
  end

  def convert_categories
    dc_categories = DCHandler::getDCCategories
    puts 'Converting ' + dc_categories.size.to_s + ' categories..'

    dc_categories.each do |cat|
      cat['name'] = Iconv::iconv('utf-8', 'iso-8859-1', cat['name']).join
      Category.create(cat) unless Category.find_by_name(cat['name'])
    end
  end

  def convert_entries
    dc_entries = DCHandler::getDCEntries
    puts 'Converting ' + dc_entries.size.to_s + ' entries..'

    dc_entries.each do |entry|
      wanted_allow_comments = entry['allow_comments']
      entry['allow_comments'] = 1

      entry['extended'] = ''
      unless entry['chapo'].nil? || entry['chapo'].empty?
        entry['extended'] = entry['body']
    entry['body'] = entry['chapo']
      end
      entry.delete('chapo')

      [ 'title', 'body', 'extended', 'author' ].each do |field|
        entry[field] = Iconv::iconv('utf-8', 'iso-8859-1', entry[field]).join
      end

      unless self.options[:author].nil?
        entry['user_id'] = self.options[:author]
      end

      puts "Adding new Article \"#{entry['title']}\"" 
      a = Article.new
      a.attributes = entry.reject { |k,v| k =~ /^(ID|cat_id)/ }
      a.save

      # Assign primary category
      unless entry['cat_id'].to_i.zero?
        puts "Assigning primary category for entry " + entry['id']

        DCHandler::getDCCategorie(entry['cat_id']).each do |c|
          c['cat_libelle'] = Iconv::iconv('utf-8', 'iso-8859-1', c['cat_libelle']).join
          a.categories.push_with_attributes(Category.find_by_name(c['cat_libelle']), :is_primary => 1) rescue nil
        end
      end

      # Fetch comments
      DCHandler::getDCEntryComments(entry['id']).each do |c|
        puts "Adding comment from #{c['author']} for entry #{entry['id']}" 
        [ 'body', 'author' ].each do |field|
          c[field] = Iconv::iconv('utf-8', 'iso-8859-1', c[field]).join
        end
        comment = a.comments.create(c)

          if c['published'].eql?('0')
            comment.mark_as_spam!
          end
      end

      a.update_attributes(:allow_comments => wanted_allow_comments)
    end
  end

  def parse_options
    self.options[:dc_prefix] = 'dc'

    OptionParser.new do |opt|
      opt.banner = 'Usage: dotclear.rb [options]'

      opt.on('--db-source-type DB SOURCE TYPE', String, 'Dotclear database type.') { |d| self.options[:dc_db_type] = d }
      opt.on('--db-source-host DB SOURCE HOST', String, 'Dotclear database host.') { |d| self.options[:dc_db_host] = d }
      opt.on('--db-source-name DB SOURCE NAME', String, 'Dotclear database name.') { |d| self.options[:dc_db_name] = d }
      opt.on('--db-source-username DB SOURCE USERNAME', String, 'Dotclear database username.') { |d| self.options[:dc_db_username] = d }
      opt.on('--db-source-password DB SOURCE PASSWORD', String, 'Dotclear database password.') { |d| self.options[:dc_db_password] = d }
      opt.on('--prefix PREFIX', String, 'Dotclear table prefix (defaults to \'dc\').') { |d| self.options[:dc_prefix] = ((d.nil? || d.empty?) ? 'dc' : d) }
      opt.on('--author author_login', String, 'Typo author login of imported articles.') do |d| 

      begin
          zeAuthor = User.find(:first, :conditions => [ 'login=?', d ])
        self.options[:author] = zeAuthor.id unless zeAuthor.nil?
        rescue
          nil
        end
    end

     opt.on_tail('-h', '--help', 'Show this message.') do
        puts opt
        exit
     end

      opt.parse!(ARGV)
    end

    unless self.options.include?(:dc_db_type)
      puts 'See dotclear.rb --help for help.'
      exit
    end

    unless self.options.include?(:dc_db_host)
      puts 'See dotclear.rb --help for help.'
      exit
    end
    unless self.options.include?(:dc_db_name)
      puts 'See dotclear.rb --help for help.'
      exit
    end
    unless self.options.include?(:dc_db_username)
      puts 'See dotclear.rb --help for help.'
      exit
    end
    unless self.options.include?(:dc_db_password)
      puts 'See dotclear.rb --help for help.'
      exit
    end
  end
end

DCMigrate.new