/[drupal]/contributions/modules/import_typepad/import_typepad.module
ViewVC logotype

Contents of /contributions/modules/import_typepad/import_typepad.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.9 - (show annotations) (download) (as text)
Fri Oct 3 00:47:47 2008 UTC (13 months, 3 weeks ago) by dgtlmoon
Branch: MAIN
CVS Tags: HEAD
Changes since 1.8: +72 -78 lines
File MIME type: text/x-php
current 6.x changes now in HEAD (how did i stuff this up?)
1 <?php
2 /**
3 * Module to import Type Pad exports into drupal
4 * Based on node_import (the cvs content importer)
5 *
6 * Nigel Sim <nigel.sim@gmail.com> 2005, 2006
7 */
8
9 ini_set('auto_detect_line_endings', TRUE);
10 define('_FILE_TYPE', 'import_typepad_file_type');
11 define('_WORKING_FILE', 'import_typepad_workingfile');
12 define('_IMPORT_TYPEPAD', 'import_typepad');
13 define('_ACTION_DELETE_FILE', 'Delete file from server');
14
15 function import_typepad_help($section) {
16 switch ($section) {
17 case 'admin/modules#description':
18 return t('Import nodes from a typepad file.');
19 case 'admin/help#import_typepad':
20 return t(' ', array('%admin-node-import_typepad' => url('admin/node/import_typepad'), '%admin-access-permission' => url('admin/access/permission')));
21 }
22 }
23
24 function import_typepad_menu($may_cache) {
25 $links = array();
26 $links[] = array('path' => 'admin/node/import_typepad', 'title' => t('type pad'), 'callback' => 'import_typepad_page', 'weight' => 5, 'access' => user_access('import nodes'));
27 $links[] = array('path' => 'admin/node/import_typepad/preview', 'title' => t('type pad'), 'callback' => 'import_typepad_preview', 'weight' => 5, 'access' => user_access('import nodes'), 'type' => MENU_CALLBACK);
28 return $links;
29 }
30
31 function import_typepad_perm() {
32 return array('import nodes');
33 }
34
35 /**
36 * Show the front page, with either the current working file, or a file selection form
37 */
38 function import_typepad_page($form_values=NULL) {
39
40 if ($edit[_WORKING_FILE]) {
41 $output .= form_item(t('File'), $edit[_WORKING_FILE] .' ('. format_size( filesize($edit[_WORKING_FILE]) ) .')<br />'. form_submit(t('Use a different file')));
42 }
43 else {
44 $form['upload_file'] = array(
45 '#type' => 'file',
46 '#title' => t('Upload Type Pad/Movable Type file'),
47 '#description' => t('The export file you wish to import'));
48 $form['serverside_file'] = array(
49 '#type' => 'textfield',
50 '#title' => t('Server side file'),
51 '#description' => t('The file located on the server you wish to import'));
52 }
53
54 // todo add an insert/update option
55 $form['submit'] = array(
56 '#type' => 'submit',
57 '#value' => t('Step 2'));
58
59 $form['#attributes'] = array('enctype' => 'multipart/form-data');
60
61 $output = drupal_get_form('typepad_step1', $form);
62
63 return $output;
64 }
65
66 /**
67 * Discover which file we are using, and move it into the appropriate position
68 */
69 function typepad_step1_validate($form_id, $form_values){
70 global $user;
71 global $base_url;
72
73 $file = file_save_upload('upload_file');
74
75 if (is_object($file) && $file->error == 0 && $file->filesize > 0) {
76 drupal_set_message(t('Using uploaded file'));
77 file_move($file->filepath, 'drupal.import_typepad.'. strtr($base_url, array('http://' => '', '/' => '.')) .'.'. $user->uid, 1);
78 //$_SESSION[_IMPORT_TYPEPAD][_WORKING_FILE] = $file->filepath;
79 variable_set(_WORKING_FILE, $file->filepath);
80 variable_set(_FILE_TYPE, 'UPLOAD');
81 } else if (strlen($form_values['serverside_file'])>0 && file_exists($form_values['serverside_file'])){
82 drupal_set_message("Using server file ".$form_values['serverside_file']);
83 // See if there was a server file
84 variable_set(_WORKING_FILE, $form_values['serverside_file']);
85 variable_set(_FILE_TYPE, 'SERVER');
86 //$_SESSION[_IMPORT_TYPEPAD][_WORKING_FILE] = $edit['serverfile'];
87 }
88
89 if ( variable_get(_WORKING_FILE, null) == null ) {
90 form_set_error('file', t('You must select a file to import.'.variable_get(_FILE_TYPE,'missing')));
91 }
92 }
93
94 /**
95 * If the validation passed then simple redirect to the preview
96 */
97 function typepad_step1_submit($form_id, $form_values){
98 return 'admin/node/import_typepad/preview';
99 }
100
101 /**
102 * If there is no file in progress then redirect to start
103 * else display preview form
104 * In due course we'll pass the preview count via the parameters
105 */
106 function import_typepad_preview($previewCount = 10) {
107 $authors = array();
108 $cats = array();
109 $output = '';
110
111 $items = _import_typepad_get_nodes( variable_get(_WORKING_FILE, null), $edit['type'], $previewCount, $authors, $cats, array());
112
113
114 // Refresh preview w/ entry count
115
116 // Previews
117 $output .= $items;
118
119 // Mappings and import
120 // Get user list
121 $users = array();
122
123 $result = db_query('SELECT uid, name FROM {users};');
124 while ($user = db_fetch_object($result)) {
125 $users[$user->uid] = $user->name;
126 }
127
128 $import_form["author_title"] = array(
129 "#type" => "markup",
130 "#value" => t("<span>Author mappings</span>"));
131 foreach ($authors as $author=>$uid){
132 $import_form[$author] = array(
133 "#type" => 'select',
134 "#title"=> $author,
135 '#options' => $users);
136 }
137
138 $import_form["taxonomy_title"] = array(
139 "#type" => "markup",
140 "#value" => t("<span>Taxonomy mappings</span>"));
141
142 foreach ($cats as $cat=>$count){
143 $item = _import_typepad_taxonomy_list($cat);
144 $item['#title'] = "$cat ($count)";
145 $import_form['taxonomy_'.str_replace(' ','_',$cat)] = $item;
146 }
147
148 $import_form["import_warning"] = array (
149 "#type" => "markup",
150 "#value" => t('<span>Importing may take awhile, do not click \'Import\' more than once. To see progress, look at the <a href="?q=admin/node" target="_new">Administer -> Content</a> page in a new window.</span>') );
151
152 $import_form['submit'] = array('#type' => 'submit', '#value' => t('Import'));
153
154 $output .= drupal_get_form('import_typepad_process', $import_form);
155
156 return $output;
157 }
158
159 /**
160 * This function returns a select box of name taxonomy_ESCAPEDNAME
161 * with all the blog categories in it.
162 */
163 function _import_typepad_taxonomy_list($name){
164 if (user_access('access content')) {
165 $default = '';
166 $vocabs = taxonomy_get_vocabularies('blog');
167 $items = array();
168 foreach ($vocabs as $vocab) {
169 $tree = taxonomy_get_tree($vocab->vid);
170 foreach ($tree as $term) {
171 $items[$term->tid] = _taxonomy_depth($term->depth) .' '.$term->name;
172 if ($name == $term->name){
173 $default = $term->tid;
174 }
175 }
176 }
177 return array(
178 "#type" => "select",
179 "#default_value" => $default,
180 "#options" => $items );
181 }
182 }
183
184 /**
185 * Simply run the import, passing the form in for the taxonomy and author maps
186 */
187 function import_typepad_process_submit($formid, $form_elements){
188 $cats = array(); // unused
189 $items = _import_typepad_get_nodes( variable_get(_WORKING_FILE, null), $edit['type'], 0, $form_elements, $cats, $form_elements);
190 if ( variable_get(_FILE_TYPE, null) == 'UPLOAD'){
191 unlink( variable_get(_WORKING_FILE, null) );
192 }
193 variable_del(_WORKING_FILE);
194 variable_del(_FILE_TYPE);
195 return 'admin/node/import_typepad';
196 }
197
198 /**
199 * Setup and perform the import
200 * STEP 3
201 */
202 function _import_typepad_import(&$edit) {
203 $output .= form_item(t('File'), $edit[_WORKING_FILE] .' ('. format_size( filesize($edit[_WORKING_FILE]) ) .')');
204 $output .= form_submit(t(_ACTION_DELETE_FILE));
205
206 $authorMap = array();
207 $cats = array();
208 foreach ($_POST['edit'] as $id=>$val){
209 if (!(strpos($id,"author_map_") === FALSE)){
210 $authorMap[substr($id, strlen("author_map_"))] = $val;
211 }
212 }
213
214 $edit['errors'] = 0;
215 $output .= _import_typepad_get_nodes($edit[_WORKING_FILE], $edit['type'], $edit['type'] == 'import_typepad' ? NULL : $edit['match'], $edit['global'], $edit['errors'], $authorMap, $cats, $edit);
216 unset($edit['match']);
217
218 return form($output);
219 }
220
221 /**
222 * Perform the delete function and return to the start page
223 */ /*
224 function import_typepad_delete($form, $edit) {
225 echo "<!-- _import_typepad_import_validate -->";
226 if ($op == t(_ACTION_DELETE_FILE)) {
227 if (file_delete($edit['file']->filepath)) {
228 drupal_set_message(t('Deleted the CSV file from the server.'));
229 }
230 $edit = array();
231 }
232 else if ($op == t('Download rows with errors')) {
233 $_SESSION['import_typepad_page'] = '_import_typepad_errors';
234 }
235 return 'admin/content/import_typepad';
236 }
237 */
238 function _import_typepad_errors($edit) {
239 header('Content-type: text/comma-separated-values');
240 header('Content-Disposition: attachment; filename="rejected-'. $edit['filename'] .'"');
241 $file = file($edit['file']->filepath);
242 $output = $file[0];
243 foreach ($edit['errors'] as $line) {
244 $output .= $file[$line];
245 }
246 return $output;
247 }
248
249 function _import_typepad_errors_validate($op, &$edit) {
250 echo "<!-- _import_typepad_import_validate -->";
251 return _import_typepad_import_validate($op, $edit);
252 }
253
254 /**
255 * Perform the importing of nodes, also for preview
256 *
257 * When there is ^M is the file it stuffs things up
258 * @param path - file path
259 * @param type
260 * @param preview - how many items to preview. If >0 then don't import.
261 * @param authors - mapping of typepad authors to drupal authors
262 * @param cats - count of different category terms (returned by reference)
263 * @param taxonomy - mapping of typepad categories to drupal categories
264 *
265 * @return preview
266 */
267 function _import_typepad_get_nodes($path, $type, $preview, &$authors, &$cats, $taxonomy) {
268 $handle = fopen($path, 'r');
269 if ($handle == null)
270 return false;
271
272 $success = 0;
273
274 $run = true;
275 $currentBlog = null;
276 $state = 0; // 0-unknown, 1-blog, 2-comment, 3-skip, 4-blog body, 5-blog excerpt
277 $previewCount = 0;
278 $blogCats = array();
279
280 $mapping = array('TITLE:'=>'title',
281 'ALLOW COMMENTS:'=>'comment', 'EMAIL:'=>'mail', 'IP:'=>'hostname', 'URL:'=>'homepage');
282
283 while ($run){
284 while ($line = fgets($handle)){
285 $rawLine = $line;
286 //echo "<!-- $rawLine -->\n";
287 $line = trim($line);
288 if ($line == "-----"){
289 $state = 0;
290 } else if ($line == "--------"){
291 $state = 0;
292 // We currently want to ignore these sections
293 } else if (in_array($line, array("EXCERPT:","KEYWORDS:"))) {
294 $state = 3;
295 } else if ($line == "EXTENDED BODY:"){
296 $state = 4;
297 } else if ($line == "BODY:"){
298 $state = 5;
299 } else if ( !(strpos($line,"COMMENT:") === FALSE) ){
300 // We are working on a comment
301 //echo "<!-- Starting new comment -->\n";
302 $state = 2;
303 $currentBlog->comments[] = new StdClass();
304 } else if ( !(strpos($line, "DATE:") === FALSE )){
305 if ($state == 1){
306 $currentBlog->created = strtotime(substr($line,strlen("DATE:")));
307 } else if ($state == 2) {
308 $currentBlog->comments[count($currentBlog->comments)-1]->timestamp = strtotime(substr($line,strlen("DATE:")));
309 } else {
310 //echo "<!-- ERROR -->\n";
311 }
312 } else if ( !(strpos($line, "STATUS:") === FALSE ) ){
313 $value = trim(substr($line,strlen("STATUS:")));
314 if (strcmp($value, "Publish") == 0){
315 $currentBlog->status = 1;
316 } else {
317 $currentBlog->status = 0;
318 }
319 } else if ( !(strpos($line,"CATEGORY:") === FALSE) ){
320 $category = trim(substr($line, strpos($line,"CATEGORY:") + strlen("CATEGORY:")));
321 $cats[$category]++;
322 $blogCats[] = $category; // Add the category to this entry
323 } else if ( !(strpos($line,"AUTHOR:") === FALSE) ){
324 // If state is unknown, then the new item is a blog, not a comment
325 if ($state == 0){
326 $state = 1;
327 // Save the last blog
328 if ($currentBlog != null){
329 $currentBlog->body = strlen(trim($currentBlog->body))==0?$currentBlog->teaser:$currentBlog->body;
330 if (!$preview){
331 $c = array();
332 foreach ($blogCats as $id=>$val){
333 $c[] = $taxonomy['taxonomy_'.str_replace(' ','_',$val)];
334 }
335 _import_typepad_save($currentBlog, $c);
336 $success++;
337 } else if ($previewCount < $preview){
338 $output .= node_view($currentBlog);
339 $previewCount++;
340 }
341 }
342
343 // Start new blog
344 $blogCats = array();
345 $currentBlog = new StdClass();
346 $currentBlog->type = 'blog';
347 $currentBlog->author = trim( substr($line, strpos($line,"AUTHOR:") + strlen("AUTHOR:")) );
348 // We generate a hash for the author name which can be used in HTML forms
349 $authorHash = 'author_map_'.str_replace(" ","_",$currentBlog->author);
350 if (!array_key_exists($authorHash, $authors)){
351 $authors[$authorHash] = 0;
352 } else if (!$preview) {
353 $currentBlog->uid = $authors[$authorHash];
354 }
355
356 $currentBlog->comments = array();
357
358 } else if ($state == 2) {
359 $currentBlog->comments[count($currentBlog->comments)-1]->name = substr($line, strlen("AUTHOR:"));
360 } else {
361 echo "<h1>ERROR 1 State = $state</h1>";
362 }
363 } else {
364 //echo "<!-- $state $rawLine -->\n";
365
366 $sep = strpos($line, ":");
367 if ($sep === false){ // || !array_key_exists($name, $mapping)){
368 $name = "";
369 $value = "";
370 } else {
371 $name = substr($line, 0, $sep+1);
372 $value = substr($line, $sep+1);
373 }
374
375 if ($state == 1){
376 $prop = $mapping[$name];
377 if (strlen($prop) > 0 )
378 $currentBlog->$prop = $value;
379 } else if ($state == 2){
380 //echo "<!-- $name $val $sep -->\n";
381 if (strlen($name) > 0 && array_key_exists($name, $mapping)){
382 $currentBlog->comments[count($currentBlog->comments)-1]->$mapping[$name] = $value;
383 } else {
384 $currentBlog->comments[count($currentBlog->comments)-1]->comment .= $rawLine;
385 }
386 } else if ($state == 3){
387 // Do nothing (Skip)
388 } else if ($state == 4){
389 // Blog body
390 $currentBlog->body .= $rawLine;
391 } else if ($state == 5){
392 $currentBlog->teaser .= $rawLine;
393 } else if ($state == 0){
394 //Do nothing, to avioid errors over nothing
395 } else {
396 echo "<h1>ERROR 2</h1>";
397 echo "<pre>$state : $line</pre>";
398 }
399 }
400 }
401 $run = false;
402 $currentBlog->body = strlen(trim($currentBlog->body))==0?$currentBlog->teaser:$currentBlog->body;
403 if (!$preview){
404 $c = array();
405 foreach ($blogCats as $id=>$val){
406 $c[] = $taxonomy['taxonomy_'.str_replace(' ','_',$val)];
407 }
408 _import_typepad_save($currentBlog, $c);
409 $success++;
410 } else if ($previewCount < $preview){
411 $output .= node_view($currentBlog);
412 $previewCount++;
413 }
414 }
415
416 fclose($handle);
417 /*
418 if ($errors) {
419 // todo use drupal_set_message?
420 drupal_set_message(t('%errors. Click \'Download rows with errors\' for a CSV file of the failed rows.', array('%errors' => format_plural(count($errors), 'There was 1 error', 'There were %count errors'))));
421 $output = form_submit(t('Download rows with errors')) . $output;
422 $errors;
423 }
424 */
425 if ($success) {
426 drupal_set_message(t('Successfully imported %count.', array('%count' => format_plural($success, '1 node', '%count nodes'))));
427 }
428
429 return $output;
430 }
431
432 /**
433 * Save the content into the database, first the blogs, then the comments
434 */
435 function _import_typepad_save($currentBlog, $terms){
436 if ($currentBlog != null){
437 // Apply all the substitutions
438 $subReplace = $_REQUEST['import_typepad_substitution_replace'];
439 $subWith = $_REQUEST['import_typepad_substitution_with'];
440
441 if (!is_null($subReplace))
442 foreach ($subReplace as $id=>$val){
443 $currentBlog->teaser = str_replace($val, $subWith[$id], $currentBlog->teaser);
444 $currentBlog->body = str_replace($val, $subWith[$id], $currentBlog->body);
445 }
446
447 // Save the entry
448 node_save($currentBlog);
449
450 // Save taxonomy items
451 $terms = array_unique($terms);
452 taxonomy_node_save($currentBlog->nid, $terms);
453
454 //echo "<!-- Number of comments = ".count($currentBlog->comments)." -->\n";
455 foreach ($currentBlog->comments as $comment){
456 // Most of the following code is ripped straight from comment.module
457 $cid = db_next_id('{comments}_cid');
458
459 // This is a comment with no parent comment (depth 0): we start
460 // by retrieving the maximum thread level.
461 $max = db_result(db_query('SELECT MAX(thread) FROM {comments} WHERE nid = %d', $edit['nid']));
462 //echo "<!-- max thread = $max -->\n";
463 // Strip the "/" from the end of the thread.
464 $max = rtrim($max, '/');
465
466 // Next, we increase this value by one. Note that we can't
467 // use 1, 2, 3, ... 9, 10, 11 because we order by string and
468 // 10 would be right after 1. We use 1, 2, 3, ..., 9, 91,
469 // 92, 93, ... instead. Ugly but fast.
470 $decimals = (string) substr($max, 0, strlen($max) - 1);
471 $units = substr($max, -1, 1);
472 if ($units) {
473 $units++;
474 }
475 else {
476 $units = 1;
477 }
478
479 if ($units == 10) {
480 $units = '90';
481 }
482
483 // Finally, build the thread field for this new comment.
484 $thread = $decimals . $units .'/';
485
486 // Type pad doesn't have threaded comments, or subject lines, so we have to improvise them
487 db_query("INSERT INTO {comments} (cid, nid, pid, uid, subject, comment, format, hostname, timestamp, status, score, users, thread, name, mail, homepage) VALUES (%d, %d, %d, %d, '%s', '%s', %d, '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s')",
488 $cid, $currentBlog->nid, 0/*pid*/, 0, "re: ".$currentBlog->title, $comment->comment, 1/*format*/, $comment->hostname, $comment->timestamp, 0/*status*/, 0/*score*/, ''/*$users*/, $thread, $comment->name, $comment->mail, $comment->homepage);
489 _comment_update_node_statistics($nid);
490 }
491 }
492 }
493 ?>

  ViewVC Help
Powered by ViewVC 1.1.2