|
@@ -125,6 +125,8 @@ class UnfuddlePeopleMigration extends UnfuddleMigration {
|
|
|
MigrateDestinationUser::getKeySchema());
|
|
|
|
|
|
// Do not map uid: this prevents user_save from creating the accounts.
|
|
|
+ $this->addFieldMapping('uid', NULL)
|
|
|
+ ->defaultValue(0);
|
|
|
|
|
|
$this->addXPathFieldMapping('created', 'created-at');
|
|
|
$this->addXPathFieldMapping('mail', 'email');
|
|
@@ -255,6 +257,7 @@ class UnfuddleProjectMigration extends UnfuddleMigration {
|
|
|
)
|
|
|
);
|
|
|
|
|
|
+ $this->dependencies = array('UnfuddlePeople');
|
|
|
$this->destination = new MigrateDestinationNode('casetracker_basic_project');
|
|
|
$this->map = new MigrateSQLMap('unfuddle_project',
|
|
|
$source_key,
|
|
@@ -263,7 +266,6 @@ class UnfuddleProjectMigration extends UnfuddleMigration {
|
|
|
$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))
|
|
@@ -271,14 +273,203 @@ class UnfuddleProjectMigration extends UnfuddleMigration {
|
|
|
$this->addXPathFieldMapping('changed', 'updated-at');
|
|
|
$this->addXPathFieldMapping('title', 'title');
|
|
|
|
|
|
- $this->addXPathFieldMapping('uid', NULL)->defaultValue(1);
|
|
|
- $this->addXPathFieldMapping('revision_uid', NULL)->defaultValue(1);
|
|
|
+ $this->addXPathFieldMapping('uid', NULL)
|
|
|
+ ->sourceMigration('UnfuddlePeople')
|
|
|
+ ->defaultValue(1);
|
|
|
+ $this->addXPathFieldMapping('revision_uid', NULL)
|
|
|
+ ->sourceMigration('UnfuddlePeople')
|
|
|
+ ->defaultValue(1);
|
|
|
$this->addXPathFieldMapping('path', 'short-name')
|
|
|
->description(t('Auto-aliased to project/(short-name)'));
|
|
|
+ $this->afterConstruct();
|
|
|
+ }
|
|
|
+
|
|
|
+ public function preparerow(stdClass $row) {
|
|
|
+ $row->xml->{'archived'} = ((int) $row->xml->{'archived'}) ? 0 : 1;
|
|
|
+ $row->xml->{'short-name'} = 'project/'. drupal_clean_css_identifier($row->xml->{'short-name'});
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class MigrateDestinationNodeCase extends MigrateDestinationNode {
|
|
|
+ public function __construct() {
|
|
|
+ parent::__construct('casetracker_basic_case');
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Could also be implemented as a migrate hook_migrate_fields() in module.
|
|
|
+ * Which is best ?
|
|
|
+ *
|
|
|
+ * (non-PHPdoc)
|
|
|
+ * @see MigrateDestinationNode::fields()
|
|
|
+ */
|
|
|
+ public function fields() {
|
|
|
+ $fields = parent::fields();
|
|
|
+ $fields += array(
|
|
|
+ 'pid' => t('Case project'),
|
|
|
+ 'case_number' => t('Case number'),
|
|
|
+ 'assign_to' => t('Case assigned to'),
|
|
|
+ 'case_priority_id' => t('Case priority'),
|
|
|
+ 'case_type_id' => t('Case type'),
|
|
|
+ 'case_status_id' => t('Case status'),
|
|
|
+ );
|
|
|
+ return $fields;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Casetracker saves its fields in a separate stdClass extra field.
|
|
|
+ *
|
|
|
+ * (non-PHPdoc)
|
|
|
+ * @see MigrateDestinationEntity::prepare()
|
|
|
+ */
|
|
|
+ public function prepare($entity, stdClass $source_row) {
|
|
|
+ $extraFields = array(
|
|
|
+ 'pid',
|
|
|
+ 'case_priority_id',
|
|
|
+ 'case_type_id',
|
|
|
+ 'assign_to',
|
|
|
+ 'case_status_id',
|
|
|
+ );
|
|
|
+
|
|
|
+ $entity->casetracker = new stdClass();
|
|
|
+ foreach ($extraFields as $extra) {
|
|
|
+ if (isset($entity->$extra)) {
|
|
|
+ $entity->casetracker->$extra = $entity->$extra;
|
|
|
+ unset($entity->extra);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $entity->casetracker->case_type_id = 9; // Bug. Case type is not a default Unfuddle field
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Import "project" ticket data from Unfuddle into CaseTracker project nodes
|
|
|
+ */
|
|
|
+class UnfuddleTicketMigration extends UnfuddleMigration {
|
|
|
+ public $unmigratedDestinations = array(
|
|
|
+ 'status',
|
|
|
+ 'promote',
|
|
|
+ 'sticky',
|
|
|
+ 'revision',
|
|
|
+ 'language',
|
|
|
+ );
|
|
|
+ public $unmigratedSources = array(
|
|
|
+ 'component-id',
|
|
|
+ 'description-format',
|
|
|
+ 'due-on',
|
|
|
+ 'hours-estimate-current',
|
|
|
+ 'hours-estimate-initial',
|
|
|
+ 'milestone-id',
|
|
|
+ 'resolution',
|
|
|
+ 'resolution-description',
|
|
|
+ 'severity-id',
|
|
|
+ 'version-id',
|
|
|
+ );
|
|
|
+
|
|
|
+ protected static function getFieldInfo() {
|
|
|
+ self::$fields = array(
|
|
|
+ 'assignee-id' => t('User Id'),
|
|
|
+ 'component-id' => t('The project component (unused)'),
|
|
|
+ 'created-at' => t('Ticket creation timestamp'),
|
|
|
+ 'description' => t('Description'),
|
|
|
+ 'description-format' => t('The ticket body format - does not match Drupal formats'),
|
|
|
+ 'due-on' => t('Timestamp the ticket should be resolved by'),
|
|
|
+ /*
|
|
|
+ 'fieldn-value-id' => t('The value for custom field n'),
|
|
|
+ */
|
|
|
+ 'hours-estimate-current' => t('The current estimate for ticket resolution'),
|
|
|
+ 'hours-estimate-initial' => t('The initial estimate for ticket resolution'),
|
|
|
+ 'milestone-id' => t('The milestone for which resolution of this ticket is due'),
|
|
|
+ 'number' => t('An apparent duplicate of the ticket id'),
|
|
|
+ 'priority' => t('The priority level for the ticket'),
|
|
|
+ 'project-id' => t('The project this ticket belongs to'),
|
|
|
+ 'reporter-id' => t('The user reporting the ticket'),
|
|
|
+ 'resolution' => t('The way the ticket was resolved'),
|
|
|
+ 'resolution-description' => t('Details about the way the ticket was resolved'),
|
|
|
+ 'severity-id' => t('The ticket severity level'),
|
|
|
+ 'status' => t('The ticket status'),
|
|
|
+ 'summary' => t('The ticket summary'),
|
|
|
+ 'updated-at' => t('Timestamp of latest ticket change'),
|
|
|
+ 'version-id' => t('The ticket version'),
|
|
|
+ 'slug' => t('Virtual: ticket summary, converted to slug'),
|
|
|
+ );
|
|
|
+
|
|
|
+ return self::$fields;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function __construct() {
|
|
|
+ parent::__construct(MigrateGroup::getInstance('Unfuddle'));
|
|
|
+ $item_xpath = '/account/projects/project/tickets/ticket';
|
|
|
+ $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->dependencies = array('UnfuddlePeople', 'UnfuddleProject');
|
|
|
+ $this->destination = new MigrateDestinationNodeCase();
|
|
|
+ $this->map = new MigrateSQLMap('unfuddle_ticket',
|
|
|
+ $source_key,
|
|
|
+ MigrateDestinationNode::getKeySchema());
|
|
|
+
|
|
|
+
|
|
|
+ $this->addXPathFieldMapping('assign_to', 'assignee-id')
|
|
|
+ ->sourceMigration('UnfuddlePeople');
|
|
|
+ $this->addXPathFieldMapping('created', 'created-at');
|
|
|
+ $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('case_priority_id', 'priority');
|
|
|
+ $this->addXPathFieldMapping('pid', 'project-id')
|
|
|
+ ->sourceMigration('UnfuddleProject');
|
|
|
+ $this->addXPathFieldMapping('uid', 'reporter-id')
|
|
|
+ ->sourceMigration('UnfuddlePeople');
|
|
|
+ $this->addXPathFieldMapping('revision_uid', 'reporter-id')
|
|
|
+ ->sourceMigration('UnfuddlePeople');
|
|
|
+ $this->addXPathFieldMapping('case_status_id', 'status');
|
|
|
+ $this->addXPathFieldMapping('case_number', 'number');
|
|
|
+ $this->addXPathFieldMapping('title', 'summary');
|
|
|
+ $this->addXPathFieldMapping('path', 'slug'); // slugged
|
|
|
+ $this->addXPathFieldMapping('changed', 'updated-at');
|
|
|
+
|
|
|
+ $this->addFieldMapping('case_type_id', NULL);
|
|
|
+
|
|
|
+ $this->afterConstruct();
|
|
|
}
|
|
|
|
|
|
public function preparerow(stdClass $row) {
|
|
|
+ /*
|
|
|
$row->xml->{'archived'} = ((int) $row->xml->{'archived'}) ? 0 : 1;
|
|
|
$row->xml->{'short-name'} = 'project/'. $row->xml->{'short-name'};
|
|
|
+ */
|
|
|
+ $row->xml->{'priority'} = 2; // "Normal"
|
|
|
+
|
|
|
+ $status = (string) $row->xml->{'status'};
|
|
|
+ $ct_status_map = array(
|
|
|
+ 'Open' => 4,
|
|
|
+ 'Resolved' => 5,
|
|
|
+ 'Deferred' => 6, // Is not a status in Unfuddle
|
|
|
+ 'Duplicate' => 7, // Is not a status in Unfuddle
|
|
|
+ 'Closed' => 8,
|
|
|
+ );
|
|
|
+
|
|
|
+ $u_status_map = array(
|
|
|
+ 'fixed' => $ct_status_map['Resolved'],
|
|
|
+ 'closed' => $ct_status_map['Closed'],
|
|
|
+ 'reopened' => $ct_status_map['Open'],
|
|
|
+ 'reassigned' => $ct_status_map['Open'],
|
|
|
+ 'new' => $ct_status_map['Open'],
|
|
|
+ 'accepted' => $ct_status_map['Open'],
|
|
|
+ );
|
|
|
+ $row->xml->{'status'} = isset($u_status_map[$status])
|
|
|
+ ? $u_status_map[$status]
|
|
|
+ : $ct_status_map['Open'];
|
|
|
+
|
|
|
+ $row->xml->{'slug'} = 'case/'. drupal_strtolower(drupal_clean_css_identifier((string) $row->xml->{'summary'}));
|
|
|
}
|
|
|
}
|