UnfuddleMigration.inc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. <?php
  2. /**
  3. * @file
  4. * Migration class to import user accounts from an Unfuddle dump.
  5. *
  6. * @copyright Coyright (c) 2011 Ouest Systèmes Informatiques (OSI, OSInet)
  7. *
  8. * @license Licensed under the General Public License version 2 and later, and the CeCILL 2.0 license.
  9. */
  10. abstract class UnfuddleMigration extends XMLMigration {
  11. public $items_url;
  12. public $item_ID_xpath = 'id';
  13. public $unmigratedDestinations = array();
  14. public $unmigratedSources = array();
  15. protected static $fields = array();
  16. public function __construct($group) {
  17. parent::__construct($group);
  18. $this->items_url = file_directory_path() . '/unfuddle/backup.xml';
  19. }
  20. public function afterConstruct() {
  21. $this->addUnmigratedDestinations($this->unmigratedDestinations, t('White hole'));
  22. $this->addUnmigratedSources($this->unmigratedSources, t('Black hole'));
  23. }
  24. /**
  25. * Return a field-name-indexed hash of field descriptions.
  26. *
  27. * @return array
  28. */
  29. protected static function getFieldInfo() {
  30. return self::$fields;
  31. }
  32. public function addXPathFieldMapping($destination_field, $source_field, $xpath = NULL) {
  33. if (!isset($xpath)) {
  34. $xpath = $source_field;
  35. }
  36. return $this->addFieldMapping($destination_field, $source_field)
  37. ->xpath($xpath);
  38. }
  39. }
  40. /**
  41. * Import "people" data from the Unfuddle backup into Drupal users
  42. */
  43. class UnfuddlePeopleMigration extends UnfuddleMigration {
  44. public $unmigratedDestinations = array(
  45. 'pass',
  46. 'roles',
  47. 'theme',
  48. 'signature',
  49. 'signature_format',
  50. 'language',
  51. 'picture',
  52. );
  53. public $unmigratedSources = array(
  54. 'account-id',
  55. 'first-name',
  56. 'identity-url',
  57. 'is-administrator',
  58. 'last-name',
  59. 'notification-frequency',
  60. 'notification-ignore-self',
  61. 'notification-last-sent',
  62. 'notification-scope-messages',
  63. 'notification-scope-milestones',
  64. 'notification-scope-notebooks',
  65. 'notification-scope-source',
  66. 'notification-scope-tickets',
  67. 'text-markup',
  68. 'updated-at',
  69. );
  70. protected static function getFieldInfo() {
  71. self::$fields = array(
  72. 'account-id' => t('Unfuddle account Id'),
  73. 'id' => t('User account ID'),
  74. 'created-at' => t('User account creation timestamp'),
  75. 'email' => t('Current email address for the account'),
  76. 'first-name' => t('User given name'),
  77. 'identity-url' => t('OpenID URL for the user account'),
  78. 'is-administrator' => t('User is an Unfuddle project administrator'),
  79. 'is-removed' => t('User account has been removed'),
  80. 'last-name' => t('User last name'),
  81. 'last-signed-in' => t('Latest login timestamp'),
  82. 'notification-frequency' => t('Unfuddle notification frequency'),
  83. 'notification-ignore-self' => t('Ignore self when sending notifications'),
  84. 'notification-last-sent' => t('Timestamp of latest notification sent'),
  85. 'notification-scope-messages' => t('Send message notifications'),
  86. 'notification-scope-milestones' => t('Send milestones notifications'),
  87. 'notification-scope-notebooks' => t('Send notebooks notifications'),
  88. 'notification-scope-source' => t('Send source notifications'),
  89. 'notification-scope-tickets' => t('Send tickets notifications'),
  90. 'text-markup' => t('Preferred markup format for issues'),
  91. 'time-zone' => t('Timezone'),
  92. 'updated-at' => t('Timestamp of latest user account change'),
  93. 'username' => t('The user account login name'),
  94. );
  95. return parent::getFieldInfo();
  96. }
  97. public function __construct() {
  98. parent::__construct(MigrateGroup::getInstance('Unfuddle'));
  99. $item_xpath = '/account/people/person';
  100. $items_class = new MigrateItemsXML($this->items_url, $item_xpath, $this->item_ID_xpath);
  101. $this->source = new MigrateSourceMultiItems($items_class, self::getFieldInfo());
  102. $source_key = array(
  103. 'id' => array(
  104. 'type' => 'int',
  105. 'unsigned' => TRUE,
  106. 'not null' => TRUE,
  107. )
  108. );
  109. $this->destination = new MigrateDestinationUser();
  110. $this->map = new MigrateSQLMap('unfuddle_people',
  111. $source_key,
  112. MigrateDestinationUser::getKeySchema());
  113. // Do not map uid: this prevents user_save from creating the accounts.
  114. $this->addXPathFieldMapping('created', 'created-at');
  115. $this->addXPathFieldMapping('mail', 'email');
  116. $this->addXPathFieldMapping('init', 'email')
  117. ->defaultValue('support@osinet.fr')
  118. ->description(t('Unfuddle does not keep the original email address'));
  119. $this->addXPathFieldMapping('status', 'is-removed')
  120. ->description(t('Inverted when converting to user.status'));
  121. $this->addXPathFieldMapping('login', 'last-signed-in');
  122. $this->addXPathFieldMapping('access', 'last-signed-in')
  123. ->description(t('Unfuddle does not log access time, only sign in.'));
  124. $this->addXPathFieldMapping('timezone', 'time-zone')
  125. ->description(t('Only Paris and London currently supported, without DST'));
  126. $this->addXPathFieldMapping('name', 'username');
  127. $this->afterConstruct();
  128. }
  129. /**
  130. * - Timestamp format conversion not needed, as per MigrationBase::timestamp()
  131. * - Invert is-removed to convert to status
  132. * - Convert Unfuddle timezones to Drupal offset seconds
  133. *
  134. * Do not forget type casts when reading SimpleXML elements.
  135. *
  136. * @param object $row
  137. */
  138. public function prepareRow(stdClass $row) {
  139. // Automatic via MigrationBase::timestamp()
  140. // $row->xml->{'created-at'} = strtotime($row->xml->{'created-at'});
  141. // $row->xml->{'last-signed-in'} = strtotime($row->xml->{'last-signed-in'});
  142. $row->xml->{'is-removed'} = ((int) $row->xml->{'is-removed'}) ? 0 : 1;
  143. // @todo TODO Primitive and does not account for DST
  144. $timezones = array(
  145. 'London' => 0,
  146. 'Paris' => 7200,
  147. );
  148. $timezone = (string) $row->xml->{'time-zone'};
  149. $row->xml->{'time-zone'} = empty($timezones[$timezone])
  150. ? 0
  151. : $timezones[$timezone];
  152. }
  153. }
  154. /**
  155. * Import "project" core data from Unfuddle into CaseTracker project nodes
  156. */
  157. class UnfuddleProjectMigration extends UnfuddleMigration {
  158. public $unmigratedDestinations = array(
  159. 'promote',
  160. 'sticky',
  161. 'revision',
  162. 'language',
  163. );
  164. public $unmigratedSources = array(
  165. 'account-id',
  166. 'assignee-on-resolve',
  167. 'backup-frequency',
  168. 'close-ticket-simultaneously-default',
  169. 'default-ticket-report-id',
  170. 'disk-usage',
  171. 'enable-time-tracking',
  172. 's3-access-key-id',
  173. 's3-backup-enabled',
  174. 's3-bucket-name',
  175. 'theme',
  176. 'categories', // @todo TODO Taxonomy ?
  177. );
  178. protected static function getFieldInfo() {
  179. self::$fields = array(
  180. 'account-id' => t('Unfuddle account Id'),
  181. 'archived' => t('Unpublished'),
  182. 'assignee-on-resolve' => t('The user being assigned a ticket once it is resolved'),
  183. 'backup-frequency' => t('Current email address for the account'),
  184. 'close-ticket-simultaneously-default' => t('Close tickets on Resolved status'),
  185. 'created-at' => t('Project creation timestamp'),
  186. 'default-ticket-report-id' => t('User reporting tickets by default'),
  187. 'description' => t('Description'),
  188. 'disk-usage' => t('Disk usage on Unfuddle, in bytes'),
  189. 'enable-time-tracking' => t('Enable issue time tracking'),
  190. 's3-access-key-id' => t('Amazon S3 key'),
  191. 's3-backup-enabled' => t('Periodic backups sent to Amazon S3'),
  192. 's3-bucket-name' => t('Amazon S3 destination bucket for backups'),
  193. 'short-name' => t('Short project name (machine name)'),
  194. 'theme' => t('Unfuddle main color for project theme'),
  195. /**
  196. * @todo TODO insert as CCK fields
  197. *
  198. 'ticket-fieldn-active' => (boolean),
  199. 'ticket-fieldn-disposition' => 'list',
  200. 'ticket-fieldn-title' => (label)
  201. *
  202. */
  203. 'title' => t('Title'),
  204. 'updated-at' => t('Timestamp of latest project change'),
  205. 'categories' => t('Categories'),
  206. /*
  207. * Ignored:
  208. components
  209. custom-field-values
  210. messages
  211. milestones
  212. notebooks
  213. severities
  214. tickets -> separate import
  215. ticket-reports (views)
  216. versions
  217. *
  218. */
  219. );
  220. return self::$fields;
  221. }
  222. public function __construct() {
  223. parent::__construct(MigrateGroup::getInstance('Unfuddle'));
  224. $item_xpath = '/account/projects/project';
  225. $items_class = new MigrateItemsXML($this->items_url, $item_xpath, $this->item_ID_xpath);
  226. $this->source = new MigrateSourceMultiItems($items_class, self::getFieldInfo());
  227. $source_key = array(
  228. 'id' => array(
  229. 'type' => 'int',
  230. 'unsigned' => TRUE,
  231. 'not null' => TRUE,
  232. )
  233. );
  234. $this->destination = new MigrateDestinationNode('casetracker_basic_project');
  235. $this->map = new MigrateSQLMap('unfuddle_project',
  236. $source_key,
  237. MigrateDestinationNode::getKeySchema());
  238. $this->addXPathFieldMapping('created', 'created-at');
  239. $this->addXPathFieldMapping('status', 'archived')
  240. ->description(t('Inverted when converting to node.status'));
  241. $this->afterConstruct();
  242. $this->addXPathFieldMapping('body', 'description')
  243. ->description(t('Applying site default input format: will often be wrong'));
  244. $this->addXPathFieldMapping('teaser', node_teaser('description', FILTER_FORMAT_DEFAULT))
  245. ->description(t('Applying site default input format: will often be wrong'));
  246. $this->addXPathFieldMapping('changed', 'updated-at');
  247. $this->addXPathFieldMapping('title', 'title');
  248. $this->addXPathFieldMapping('uid', NULL)->defaultValue(1);
  249. $this->addXPathFieldMapping('revision_uid', NULL)->defaultValue(1);
  250. $this->addXPathFieldMapping('path', 'short-name')
  251. ->description(t('Auto-aliased to project/(short-name)'));
  252. }
  253. public function preparerow(stdClass $row) {
  254. $row->xml->{'archived'} = ((int) $row->xml->{'archived'}) ? 0 : 1;
  255. $row->xml->{'short-name'} = 'project/'. $row->xml->{'short-name'};
  256. }
  257. }