items_url = file_directory_path() . '/unfuddle/backup.xml'; } public function afterConstruct() { $this->addUnmigratedDestinations($this->unmigratedDestinations, t('White hole')); $this->addUnmigratedSources($this->unmigratedSources, t('Black hole')); } /** * Return a field-name-indexed hash of field descriptions. * * @return array */ protected static function getFieldInfo() { return self::$fields; } public function addXPathFieldMapping($destination_field, $source_field, $xpath = NULL) { if (!isset($xpath)) { $xpath = $source_field; } return $this->addFieldMapping($destination_field, $source_field) ->xpath($xpath); } } /** * Import "people" data from the Unfuddle backup into Drupal users */ class UnfuddlePeopleMigration extends UnfuddleMigration { public $unmigratedDestinations = array( 'pass', 'roles', 'theme', 'signature', 'signature_format', 'language', 'picture', ); public $unmigratedSources = array( 'account-id', 'first-name', 'identity-url', 'is-administrator', 'last-name', 'notification-frequency', 'notification-ignore-self', 'notification-last-sent', 'notification-scope-messages', 'notification-scope-milestones', 'notification-scope-notebooks', 'notification-scope-source', 'notification-scope-tickets', 'text-markup', 'updated-at', ); protected static function getFieldInfo() { self::$fields = array( 'account-id' => t('Unfuddle account Id'), 'id' => t('User account ID'), 'created-at' => t('User account creation timestamp'), 'email' => t('Current email address for the account'), 'first-name' => t('User given name'), 'identity-url' => t('OpenID URL for the user account'), 'is-administrator' => t('User is an Unfuddle project administrator'), 'is-removed' => t('User account has been removed'), 'last-name' => t('User last name'), 'last-signed-in' => t('Latest login timestamp'), 'notification-frequency' => t('Unfuddle notification frequency'), 'notification-ignore-self' => t('Ignore self when sending notifications'), 'notification-last-sent' => t('Timestamp of latest notification sent'), 'notification-scope-messages' => t('Send message notifications'), 'notification-scope-milestones' => t('Send milestones notifications'), 'notification-scope-notebooks' => t('Send notebooks notifications'), 'notification-scope-source' => t('Send source notifications'), 'notification-scope-tickets' => t('Send tickets notifications'), 'text-markup' => t('Preferred markup format for issues'), 'time-zone' => t('Timezone'), 'updated-at' => t('Timestamp of latest user account change'), 'username' => t('The user account login name'), ); return parent::getFieldInfo(); } public function __construct() { parent::__construct(MigrateGroup::getInstance('Unfuddle')); $item_xpath = '/account/people/person'; $items_class = new MigrateItemsXML($this->items_url, $item_xpath, $this->item_ID_xpath); $this->source = new MigrateSourceMultiItems($items_class, self::getFieldInfo()); $source_key = array( 'id' => array( 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ) ); $this->destination = new MigrateDestinationUser(); $this->map = new MigrateSQLMap('unfuddle_people', $source_key, MigrateDestinationUser::getKeySchema()); // Do not map uid: this prevents user_save from creating the accounts. $this->addXPathFieldMapping('created', 'created-at'); $this->addXPathFieldMapping('mail', 'email'); $this->addXPathFieldMapping('init', 'email') ->defaultValue('support@osinet.fr') ->description(t('Unfuddle does not keep the original email address')); $this->addXPathFieldMapping('status', 'is-removed') ->description(t('Inverted when converting to user.status')); $this->addXPathFieldMapping('login', 'last-signed-in'); $this->addXPathFieldMapping('access', 'last-signed-in') ->description(t('Unfuddle does not log access time, only sign in.')); $this->addXPathFieldMapping('timezone', 'time-zone') ->description(t('Only Paris and London currently supported, without DST')); $this->addXPathFieldMapping('name', 'username'); $this->afterConstruct(); } /** * - Timestamp format conversion not needed, as per MigrationBase::timestamp() * - Invert is-removed to convert to status * - Convert Unfuddle timezones to Drupal offset seconds * * Do not forget type casts when reading SimpleXML elements. * * @param object $row */ public function prepareRow(stdClass $row) { // Automatic via MigrationBase::timestamp() // $row->xml->{'created-at'} = strtotime($row->xml->{'created-at'}); // $row->xml->{'last-signed-in'} = strtotime($row->xml->{'last-signed-in'}); $row->xml->{'is-removed'} = ((int) $row->xml->{'is-removed'}) ? 0 : 1; // @todo TODO Primitive and does not account for DST $timezones = array( 'London' => 0, 'Paris' => 7200, ); $timezone = (string) $row->xml->{'time-zone'}; $row->xml->{'time-zone'} = empty($timezones[$timezone]) ? 0 : $timezones[$timezone]; } } /** * Import "project" core data from Unfuddle into CaseTracker project nodes */ class UnfuddleProjectMigration extends UnfuddleMigration { public $unmigratedDestinations = array( 'promote', 'sticky', 'revision', 'language', ); public $unmigratedSources = array( 'account-id', 'assignee-on-resolve', 'backup-frequency', 'close-ticket-simultaneously-default', 'default-ticket-report-id', 'disk-usage', 'enable-time-tracking', 's3-access-key-id', 's3-backup-enabled', 's3-bucket-name', 'theme', 'categories', // @todo TODO Taxonomy ? ); protected static function getFieldInfo() { self::$fields = array( 'account-id' => t('Unfuddle account Id'), 'archived' => t('Unpublished'), 'assignee-on-resolve' => t('The user being assigned a ticket once it is resolved'), 'backup-frequency' => t('Current email address for the account'), 'close-ticket-simultaneously-default' => t('Close tickets on Resolved status'), 'created-at' => t('Project creation timestamp'), 'default-ticket-report-id' => t('User reporting tickets by default'), 'description' => t('Description'), 'disk-usage' => t('Disk usage on Unfuddle, in bytes'), 'enable-time-tracking' => t('Enable issue time tracking'), 's3-access-key-id' => t('Amazon S3 key'), 's3-backup-enabled' => t('Periodic backups sent to Amazon S3'), 's3-bucket-name' => t('Amazon S3 destination bucket for backups'), 'short-name' => t('Short project name (machine name)'), 'theme' => t('Unfuddle main color for project theme'), /** * @todo TODO insert as CCK fields * 'ticket-fieldn-active' => (boolean), 'ticket-fieldn-disposition' => 'list', 'ticket-fieldn-title' => (label) * */ 'title' => t('Title'), 'updated-at' => t('Timestamp of latest project change'), 'categories' => t('Categories'), /* * Ignored: components custom-field-values messages milestones notebooks severities tickets -> separate import ticket-reports (views) versions * */ ); return self::$fields; } public function __construct() { parent::__construct(MigrateGroup::getInstance('Unfuddle')); $item_xpath = '/account/projects/project'; $items_class = new MigrateItemsXML($this->items_url, $item_xpath, $this->item_ID_xpath); $this->source = new MigrateSourceMultiItems($items_class, self::getFieldInfo()); $source_key = array( 'id' => array( 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ) ); $this->destination = new MigrateDestinationNode('casetracker_basic_project'); $this->map = new MigrateSQLMap('unfuddle_project', $source_key, MigrateDestinationNode::getKeySchema()); $this->addXPathFieldMapping('created', 'created-at'); $this->addXPathFieldMapping('status', 'archived') ->description(t('Inverted when converting to node.status')); $this->afterConstruct(); $this->addXPathFieldMapping('body', 'description') ->description(t('Applying site default input format: will often be wrong')); $this->addXPathFieldMapping('teaser', node_teaser('description', FILTER_FORMAT_DEFAULT)) ->description(t('Applying site default input format: will often be wrong')); $this->addXPathFieldMapping('changed', 'updated-at'); $this->addXPathFieldMapping('title', 'title'); $this->addXPathFieldMapping('uid', NULL)->defaultValue(1); $this->addXPathFieldMapping('revision_uid', NULL)->defaultValue(1); $this->addXPathFieldMapping('path', 'short-name') ->description(t('Auto-aliased to project/(short-name)')); } public function preparerow(stdClass $row) { $row->xml->{'archived'} = ((int) $row->xml->{'archived'}) ? 0 : 1; $row->xml->{'short-name'} = 'project/'. $row->xml->{'short-name'}; } }