diff --git a/3.0/modules/g1_import/controllers/admin_g1_import.php b/3.0/modules/g1_import/controllers/admin_g1_import.php new file mode 100644 index 00000000..40c96c46 --- /dev/null +++ b/3.0/modules/g1_import/controllers/admin_g1_import.php @@ -0,0 +1,126 @@ +page_title = t('Gallery 1 import'); + $view->content = new View('admin_g1_import.html'); + + if (is_dir(g1_import::$album_dir)) { + $view->content->g1_stats = $g1_stats = g1_import::g1_stats(); + $view->content->g3_stats = $g3_stats = g1_import::g3_stats(); + $view->content->g1_sizes = g1_import::common_sizes(); + $view->content->g1_version = g1_import::version(); + + // Don't count tags because we don't track them in g1_map + $view->content->g1_resource_count = + $g1_stats['users'] + $g1_stats['groups'] + $g1_stats['albums'] + + $g1_stats['photos'] + $g1_stats['movies'] + $g1_stats['comments']; + $view->content->g3_resource_count = + $g3_stats['user'] + $g3_stats['group'] + $g3_stats['album'] + + $g3_stats['item'] + $g3_stats['comment'] + $g3_stats['tag']; + } + + $view->content->form = $this->_get_import_form(); + $view->content->version = ''; + $view->content->thumb_size = module::get_var('gallery', 'thumb_size'); + $view->content->resize_size = module::get_var('gallery', 'resize_size'); + + if (g1_import::is_initialized()) { + if ((bool)ini_get('eaccelerator.enable') || (bool)ini_get('xcache.cacher')) { + message::warning(t('The eAccelerator and XCache PHP performance extensions are known to cause issues. If you\'re using either of those and are having problems, please disable them while you do your import. Add the following lines:
%lines
to gallery3/.htaccess and remove them when the import is done.', array('lines' => "\n\n php_value eaccelerator.enable 0\n php_value xcache.cacher off\n php_value xcache.optimizer off\n\n"))); + } + + foreach (array('notification', 'search', 'exif') as $module_id) { + if (module::is_active($module_id)) { + message::warning( + t('Deactivating the %module_id module during your import will make it faster', + array('url' => url::site('admin/modules'), 'module_id' => $module_id))); + } + } + } else if (g1_import::is_configured()) { + $view->content->form->configure_g1_import->albums_path->add_error('invalid', 1); + } + print $view; + } + + public function save() { + access::verify_csrf(); + + $form = $this->_get_import_form(); + if ($form->validate()) { + $albums_path = $form->configure_g1_import->albums_path->value; + if (!is_file($albums_path) && file_exists("$albums_path/albums.php")) { + $albums_path = "$albums_path/albums.php"; + } + + if (($g1_init_error = g1_import::is_valid_albums_path($albums_path)) == 'ok') { + message::success(t('Gallery 1 path saved')); + module::set_var('g1_import', 'albums_path', $albums_path); + url::redirect('admin/g1_import'); + } else { + $form->configure_g1_import->albums_path->add_error($g1_init_error, 1); + } + } + + $view = new Admin_View('admin.html'); + $view->content = new View('admin_g1_import.html'); + $view->content->form = $form; + print $view; + } + + public function autocomplete() { + $directories = array(); + $path_prefix = Input::instance()->get('q'); + foreach (glob('{$path_prefix}*') as $file) { + if (is_dir($file) && !is_link($file)) { + $directories[] = $file; + + // If we find an albums.php, include it as well + if (file_exists("$file/albums.php")) { + $directories[] = "$file/albums.php"; + } + } + } + + print implode("\n", $directories); + } + + private function _get_import_form() { + $albums_path = module::get_var('g1_import', 'albums_path', ''); + $form = new Forge( + 'admin/g1_import/save', '', 'post', array('id' => 'g-admin-configure-g1-import-form')); + $group = $form->group('configure_g1_import')->label(t('Configure Gallery 1 Import')); + $group->input('albums_path')->label(t('Filesystem path to your Gallery 1 albums.php file')) + ->value($albums_path); + $group->albums_path->error_messages( + 'invalid', t('The path you entered is not a Gallery 1 installation.')); + $group->albums_path->error_messages( + 'broken', t('Your Gallery 1 install isn\'t working properly. Please verify it!')); + $group->albums_path->error_messages( + 'missing', t('The path you entered does not exist.')); + $group->submit('')->value(g1_import::$album_dir=='' ? t('Change') : t('Continue')); + return $form; + } +} \ No newline at end of file diff --git a/3.0/modules/g1_import/controllers/g1.php b/3.0/modules/g1_import/controllers/g1.php new file mode 100644 index 00000000..53458baa --- /dev/null +++ b/3.0/modules/g1_import/controllers/g1.php @@ -0,0 +1,93 @@ +get('path'); + $page = $input->get('page'); + if(!is_numeric($page)) $page = ''; + + if($path=='view_album.php' || $path=='slideshow.php') $path = $input->get('set_albumName'); + if($path=='view_photo.php') $path = $input->get('set_albumName').'/'.$input->get('id'); + + if($path=='main.php') { //we do only name based g2 mapping here + $item = item::root(); + access::required('view', $item); + url::redirect($item->abs_url(), '301'); + } + + // Item names come in as FolderX/ItemX + $album = 0; + $pos = strrpos($path, '/'); + if($pos!==false) { + // Get ItemX into g1_item + $g1_item = substr($path,$pos+1); + // Get FolderX into g1_item + $g1_album = substr($path,0,$pos); + } + else { + $album = 1; + $g1_item = ''; + $g1_album = $path; + } + + // Only binary files (the item itself, not the html) may have file extensions + $binary = 0; + $pos = strrpos($g1_item, '.'); + if($pos!==false) { + $binary = 1; + $g1_item = substr($g1_item, 0, $pos); + } + + $mapping = ORM::factory('g1_map')->where('album', '=', $g1_album)->where('item', '=', $g1_item)->where('resource_type', '=', $album ? 'album':'item')->find(); + if(!$mapping->loaded()) { + throw new Kohana_404_Exception(); + } + $item = ORM::factory('item', $mapping->id); + if (!$item->loaded()) { + throw new Kohana_404_Exception(); + } + access::required('view', $item); + + if($binary) { + url::redirect($item->file_url(true), '301'); + } + else { + $url = $item->abs_url(); + if($page!='') { + $url .= (strpos($url,'?')!==false ? '&':'?').'page='.$page; + } + url::redirect($url, '301'); + } + } +} diff --git a/3.0/modules/g1_import/data/broken-image.gif b/3.0/modules/g1_import/data/broken-image.gif new file mode 100644 index 00000000..fb9c8240 Binary files /dev/null and b/3.0/modules/g1_import/data/broken-image.gif differ diff --git a/3.0/modules/g1_import/helpers/Gallery1DataParser.php b/3.0/modules/g1_import/helpers/Gallery1DataParser.php new file mode 100644 index 00000000..2686e27d --- /dev/null +++ b/3.0/modules/g1_import/helpers/Gallery1DataParser.php @@ -0,0 +1,413 @@ + $parentName) { + if (!isset($tempAlbums[$myName])) { + $tempAlbums[$myName] = array(); + } + if (empty($parentName) || $parentName == '.root') { + $hierarchy[$myName] = &$tempAlbums[$myName]; + } else { + if (!isset($tempAlbums[$parentName])) { + $tempAlbums[$parentName] = array(); + } + $tempAlbums[$parentName][$myName] = &$tempAlbums[$myName]; + } + } + return array(null, $hierarchy); + } + + /** + * Fetch an array of albums with no parents + * + * @param string $path Path to albums directory + * @return array GalleryStatus a status code, + * array of albumnames + */ + function getRootAlbums($path) { + + list ($ret, $albumOrder) = Gallery1DataParser::loadFile($path . 'albumdb.dat'); + if ($ret) { + return array($ret, null); + } + + foreach ($albumOrder as $albumName) { + list ($ret, $albumFields) = + Gallery1DataParser::loadAlbumFields($path . $albumName . DIRECTORY_SEPARATOR); + if ($ret) { + return array($ret,''); + } + if ($albumFields['parentAlbumName'] == '.root') { + $rootAlbums[] = $albumName; + } + } + return array(null, $rootAlbums); + } + + /** + * Load and return album metadata from given directory + * + * @param string $path Path to album directory + * @return array GalleryStatus a status code, + * object Unserialized album metadata + */ + function loadAlbumFields($path) { + + $tmp = trim($path); + if ($tmp[strlen($tmp)-1] != DIRECTORY_SEPARATOR) { + $tmp .= DIRECTORY_SEPARATOR; + } + $path = trim($tmp); + $albumPath = explode(DIRECTORY_SEPARATOR, $path); + $albumName = $albumPath[count($albumPath)-2]; + list ($ret, $album) = Gallery1DataParser::loadFile($path . 'album.dat'); + if ($ret) { + return array($ret, null); + } + $album->fields['name'] = $albumName; + if (!$album->fields['parentAlbumName']) { + $album->fields['parentAlbumName'] = '.root'; + } + return array(null, $album->fields); + } + + /** + * Count the number of photos in an album dir + * + * @param string $path Path to album directory + * @return array GalleryStatus a status code, + * integer Count of photos + */ + function getPhotoCount($path) { + list ($ret, $photos) = Gallery1DataParser::loadFile($path . 'photos.dat'); + if ($ret) { + return array($ret, null); + } + $photoCount = count($photos); + return array(null, $photoCount); + } + + /** + * Count the photo data from an album dir + * + * @param string $path Path to album directory + * @return array GalleryStatus a status code, + * array Galleryphotos + */ + function getPhotos($path) { + + list ($ret, $photos) = Gallery1DataParser::loadFile($path . DIRECTORY_SEPARATOR . 'photos.dat'); + if ($ret) { + return array($ret, null); + } + return array(null, $photos); + } + + /** + * Load user uids from path + * + * @param string $path Path to album directory + * @return array GalleryStatus a status code, + * array Associative array of uids and usernames + */ + function getUserUids($path) { + static $uids; + if (!isset($uids[$path])) { + if (!isset($uids)) { + $uids = array(); + } + + list ($ret, $userDB) = + Gallery1DataParser::loadFile($path . '.users' . DIRECTORY_SEPARATOR . 'userdb.dat'); + if ($ret) { + return array($ret, null); + } + $uids[$path] = array(); + foreach ($userDB->userMap as $username => $uid) { + if (Gallery1DataParser::isValidUid($path, $uid) + && !Gallery1DataParser::isValidUid($path, $username) + && !preg_match('/nobody|everybody|loggedin/i', $username)) { + $uids[$path][$uid] = $username; + } + } + } + return array(null, $uids[$path]); + } + + /** + * Validate user id string from gallery v1.x.x + * + * @param string $uid Uid to be tested + * @return boolean + */ + function isValidUidString($uid) { + if (preg_match('/^\d{9,}_\d+$/', $uid)) { + return TRUE; + } else { + return FALSE; + } + } + + /** + * Validate user id from gallery v1.x.x + * + * @param string $path + * @param string $uid Uid to be tested + * @return boolean + */ + function isValidUid($path, $uid) { + static $valid; + if (!isset($valid[$path][$uid])) { + if (!isset($valid)) { + $valid = array(); + } + if (!isset($valid[$path])) { + $valid[$path] = array(); + } + if (Gallery1DataParser::isValidUidString($uid)) { + list ($ret, $fields) = Gallery1DataParser::getUserFieldsByUid($path, $uid); + if (!$ret) { + $valid[$path][$uid] = TRUE; + } else { + $valid[$path][$uid] = FALSE; + } + } else { + $valid[$path][$uid] = FALSE; + } + } + return $valid[$path][$uid]; + } + + /** + * Load user metadata given a path and uid + * + * @param string $path Path to album directory + * @param string $uid Uid to import + * @return array GalleryStatus a status code, + * array User metadata + */ + function getUserFieldsByUid($path, $uid) { + static $fields; + + if (!isset($fields[$path][$uid])) { + if (!isset($fields)) { + $fields = array(); + } + if (!isset($fields[$path])) { + $fields[$path] = array(); + } + $fields[$path][$uid] = array(); + if (Gallery1DataParser::isValidUidString($uid)) { + list ($ret, $user) = Gallery1DataParser::loadFile($path . '.users' . DIRECTORY_SEPARATOR . $uid); + if ($ret) { + return array($ret, null); + } + foreach ($user as $key => $value) { + $fields[$path][$uid][$key] = $value; + } + } + } + return array(null, $fields[$path][$uid]); + } + + /** + * Load user metadata given a path and username + * + * @param string $path Path to album directory + * @param string $username Username to import + * @return array GalleryStatus a status code, + * array User metadata + */ + function getUserFieldsByUsername($path, $username) { + list ($ret, $uids) = Gallery1DataParser::getUserUids($path); + if ($ret) { + return array($ret, null); + } + $usernames = array_flip($uids); + $uid = $usernames[$username]; + list ($ret, $fields) = Gallery1DataParser::getUserFieldsByUid($path, $uid); + if ($ret) { + return array($ret, null); + } + return array(null, $fields); + } +} + + +/* Define these classes so that unserialize can use them */ +/** + * A stub class into which various G1 objects can be unserialized. + */ +class G1AlbumDB{ } +/** + * A stub class into which various G1 objects can be unserialized. + */ +class Album { } +/** + * A stub class into which various G1 objects can be unserialized. + */ +class Gallery_UserDB { } +/** + * A stub class into which various G1 objects can be unserialized. + */ +class Gallery_User { } +/** + * A stub class into which various G1 objects can be unserialized. + */ +class AlbumItem { } +/** + * A stub class into which various G1 objects can be unserialized. + */ +class G1Img { } +/** + * A stub class into which various G1 objects can be unserialized. + */ +class Comment { } diff --git a/3.0/modules/g1_import/helpers/g1_import.php b/3.0/modules/g1_import/helpers/g1_import.php new file mode 100644 index 00000000..172506e3 --- /dev/null +++ b/3.0/modules/g1_import/helpers/g1_import.php @@ -0,0 +1,1085 @@ +app->albumDir = "/home/t-horner.com/www/albums"; + if(preg_match('/\$gallery *-> *app *-> *albumDir *= *["\']([^"\']*)["\']/i',$line,$result)==1 && count($result)==2 && $result[1]!='') + $albumDir = $result[1]; + if(preg_match('/\$gallery *-> *app *-> *albumDirURL *= *["\']([^"\']*)["\']/i',$line,$result)==1 && count($result)==2 && $result[1]!='') + $albumUrl = $result[1]; + if(preg_match('/\$gallery *-> *app *-> *photoAlbumURL *= *["\']([^"\']*)["\']/i',$line,$result)==1 && count($result)==2 && $result[1]!='') + $galleryUrl = $result[1]; + if(preg_match('/\$gallery *-> *app *-> *default\[ *["\']thumb_size["\'] *\] *= *["\']([^"\']*)["\']/i',$line,$result)==1 && count($result)==2 && $result[1]!='') + $thumbSize = $result[1]; + if(preg_match('/\$gallery *-> *app *-> *default\[ *["\']resize_size["\'] *\] *= *["\']([^"\']*)["\']/i',$line,$result)==1 && count($result)==2 && $result[1]!='') + $resizeSize = $result[1]; + } + + if ($albumDir=='' || !is_dir($albumDir) || $albumUrl=='' || $galleryUrl=='') { + return 'broken'; + } + + self::$album_dir = $albumDir; + self::$album_url = $albumUrl; + self::$gallery_url = $galleryUrl; + self::$thumb_size = $thumbSize; + self::$resize_size = $resizeSize; + self::$gallery_dir = dirname($albums_path); + + + $version = ''; + $version_path = dirname($albums_path).DIRECTORY_SEPARATOR.'Version.php'; + if (!is_file($version_path)) { + $version_path = dirname($albums_path).DIRECTORY_SEPARATOR.'version.php'; + } + if (is_file($version_path)) { + foreach(file($version_path) as $line) { + //look for a line like: $gallery->version = '1.5.10'; + if(preg_match('/\$gallery *-> *version *= *["\']([^"\']*)["\']/i',$line,$result)==1 && count($result)==2 && $result[1]!='') + $version = $result[1]; + } + } + else { + $version = '1.x'; + } + self::$version = $version; + + + return 'ok'; + } + + /** + * Return the version of Gallery 1 (eg "1.5.10") + */ + static function version() { + if(!self::is_initialized()) + return '1'; + return self::$version; + } + + static function recursiveCountGallery($albumDir, $array, $level) { + $countAlbum = 0; + foreach($array as $key => $value) { + if($key!='') { + $countAlbum++; + self::$albums_flat[] = $level.':'.$key; + + require_once('Gallery1DataParser.php'); + list($result, $items) = Gallery1DataParser::getPhotos($albumDir.$key.DIRECTORY_SEPARATOR); + + if($result==null) + foreach($items as $object) { + + if(isset($object->image) && is_a($object->image, 'G1Img')) { + + $item = $key.DIRECTORY_SEPARATOR.$object->image->name; + self::$queued_items[] = $item; + if(isset($object->comments) && is_array($object->comments) && count($object->comments)) { + + $comments = array(); + foreach ($object->comments as $comment) { + if (is_a($comment, 'Comment')) { + $comments[] = array( 'commentText' => $comment->commentText + ,'name' => $comment->name + ,'UID' => $comment->UID + ,'datePosted' => $comment->datePosted + ,'IPNumber' => $comment->IPNumber + ); + } + } + self::$queued_comments[] = array( $item => $comments ); + } + + if(isset($object->highlight) && $object->highlight==1 && isset($object->highlightImage) && is_a($object->highlightImage, 'G1Img')) { + self::$queued_highlights[] = $level.':'.$key.DIRECTORY_SEPARATOR.$object->highlightImage->name; + } + } + else if(isset($object->isAlbumName) && $object->isAlbumName!='') { + + if(isset($object->highlight) && $object->highlight==1 && isset($object->highlightImage) && is_a($object->highlightImage, 'G1Img')) { + self::$queued_highlights[] = $level.':'.$key.DIRECTORY_SEPARATOR.$object->highlightImage->name; + } + if(isset($object->hidden) && $object->hidden==1) { + self::$albums_hidden[$object->isAlbumName] = 1; + } + } + else { + g1_import::log('Invalid object found: '.print_r($object, true)); + } + + } + } + if(is_array($value) && count($value)>0) { + $countAlbum += g1_import::recursiveCountGallery($albumDir, $value, $level+1); + } + } + return $countAlbum; + } + + /** + * Return a set of statistics about the number of users, groups, albums, photos, movies and + * comments available for import from the Gallery 1 instance. + */ + static function g1_stats() { + $stats['users'] = 0; + $stats['groups'] = 0; + $stats['albums'] = 0; + $stats['photos'] = 0; + $stats['movies'] = 0; + $stats['comments'] = 0; + $stats['tags'] = 0; + + $albumDir = self::$album_dir; + if(substr($albumDir,-1)!=DIRECTORY_SEPARATOR) $albumDir.=DIRECTORY_SEPARATOR; + + require_once('Gallery1DataParser.php'); + if(Gallery1DataParser::isValidAlbumsPath($albumDir)) { + if(count(self::$tree)==0) { + list($result, $tree) = Gallery1DataParser::getAlbumHierarchy($albumDir); + if($result==null) self::$tree = $tree; + } + + list($result, $uids) = Gallery1DataParser::getUserUids($albumDir); + if($result==null) $stats['users'] = count($uids); + + self::$queued_items = array(); + self::$queued_comments = array(); + self::$queued_highlights = array(); + self::$albums_flat = array(); + self::$albums_hidden = array(); + if(count(self::$tree)) $stats['albums'] = 1 /* <= THE ROOT ALBUM!!!*/ + g1_import::recursiveCountGallery($albumDir, self::$tree, 0); + + $stats['photos'] = count(self::$queued_items); + foreach(self::$queued_comments as $element) { + foreach($element as $item => $comments) { + $stats['comments'] += count($comments); + } + } + arsort(self::$queued_highlights); + $stats['highlights'] = count(self::$queued_highlights); + + arsort(self::$albums_flat); + foreach(self::$albums_flat as $key => $value) { + $pos = strpos($value, ':'); + if($pos!==false) self::$albums_flat[$key] = substr($value, $pos+1); + } + } + + return $stats; + } + + /** + * Return a set of statistics about the number of users, groups, albums, photos, movies and + * comments already imported into the Gallery 3 instance. + */ + static function g3_stats() { + $g3_stats = array( + 'album' => 0, 'comment' => 0, 'item' => 0, 'user' => 0, 'group' => 0, 'tag' => 0); + foreach (db::build() + ->select('resource_type') + ->select(array('C' => 'COUNT("*")')) + ->from('g1_maps') + ->where('resource_type', 'IN', array('album', 'comment', 'item', 'user', 'group')) + ->group_by('resource_type') + ->execute() as $row) { + $g3_stats[$row->resource_type] = $row->C; + } + return $g3_stats; + } + + /** + * Import a single album. + */ + static function import_album(&$queue) { + $messages = array(); + + // The queue is a set of nested associative arrays where the key is the album id and the + // value is an array of similar arrays. We'll do a breadth first tree traversal using the + // queue to keep our state. Doing it breadth first means that the parent will be created by + // the time we get to the child. + + // Dequeue the current album and enqueue its children + list($album, $tree) = each($queue); + unset($queue[$album]); + + foreach($tree as $key => $value) { + $queue[$album.'/'.$key] = $value; + } + + // Special handling for the root album + if ($album == '') { + if (!self::map('', '', 'album')) { + $album = item::root(); + self::set_map($album->id, '', '', 'album'); + } + return $messages; + } + + // Album names come in as /Folder1/Folder2/FolderX + $pos = strrpos($album, '/'); + if($pos===false) { + return $messages; + } + + // Get FolderX into g1_album + $parent = substr($album,0,$pos); + $g1_album = substr($album,$pos+1); + + // Reduce parent to Folder2 + $pos = strrpos($parent, '/'); + if($pos!==false) { + $parent = substr($parent,$pos+1); + } + + // Skip already-existing albums + if (self::map($g1_album, '', 'album')) { + $messages[] = t('Skipping already existing album %album.', array('album' => $parent.'/'.$g1_album)); + return $messages; + } + + $album_id = self::map($parent, '', 'album'); + if (!$album_id) { + $messages[] = t('Album %name not found', array('name' => $parent)); + return $messages; + } + + g1_import::debug( t('Now importing album %album.', array('album' => $parent.'/'.$g1_album)) ); + + + $albumDir = self::$album_dir; + if(substr($albumDir,-1)!=DIRECTORY_SEPARATOR) $albumDir.=DIRECTORY_SEPARATOR; + $importDir = $albumDir.$g1_album.DIRECTORY_SEPARATOR; + + + $parent = ORM::factory('item', $album_id); + + $album = ORM::factory('item'); + $album->type = 'album'; + $album->parent_id = $album_id; + g1_import::set_album_values($album, $g1_album); + + try { + $album->validate(); + } catch (ORM_Validation_Exception $e) { + throw new G1_Import_Exception( + t('Failed to validate Gallery 1 album with name %name.', + array('name' => $g1_album)), + $e); + } + + try { + $album->save(); + self::set_map($album->id, $g1_album, '', 'album'); + } catch (Exception $e) { + throw new G1_Import_Exception( + t('Failed to import Gallery 1 album with name %name.', + array('name' => $g1_album)), + $e); + } + + try { + require_once('Gallery1DataParser.php'); + list($result, $items) = Gallery1DataParser::getPhotos($importDir); + if($result==null) + foreach($items as $object) { + if(isset($object->highlight) && $object->highlight==1 && isset($object->highlightImage) && is_a($object->highlightImage, 'G1Img')) { + $g1_path = $importDir.$object->highlightImage->name.'.'.$object->highlightImage->type; + if (is_file($g1_path) && @copy($g1_path, $album->thumb_path())) { + $album->thumb_height = $object->highlightImage->height; + $album->thumb_width = $object->highlightImage->width; + $album->thumb_dirty = false; + $album->save(); + } + } + } + } catch (Exception $e) { + throw new G1_Import_Exception( + t('Failed to copy thumb for album %name.', + array('name' => $g1_album)), + $e); + } + + try { + if(isset(self::$albums_hidden[$g1_album])) { + access::deny(identity::everybody(), 'view', $album); + } + } catch (Exception $e) { + throw new G1_Import_Exception( + t('Failed to set access permission for hidden album %name.', + array('name' => $g1_album)), + $e); + } + + return $messages; + } + + /** + * Transfer over all the values from a G1 album to a G3 album. + */ + static function set_album_values($album, $g1_album) { + $albumDir = self::$album_dir; + if(substr($albumDir,-1)!=DIRECTORY_SEPARATOR) $albumDir.=DIRECTORY_SEPARATOR; + $albumDir .= $g1_album; + if(substr($albumDir,-1)!=DIRECTORY_SEPARATOR) $albumDir.=DIRECTORY_SEPARATOR; + + require_once('Gallery1DataParser.php'); + list($result, $fields) = Gallery1DataParser::loadAlbumFields($albumDir); + + $album->name = $fields['name']; + $album->slug = $fields['name']; // <= verification fails if this property has not been set!!! + $album->title = utf8_encode(self::_decode_html_special_chars(trim($fields['title']))); + $album->title or $album->title = $album->name; + $album->description = utf8_encode(self::_decode_html_special_chars(trim($fields['description']))); + //$album->owner_id = self::map($g1_album->getOwnerId()); + try { + $album->view_count = (int) $fields['clicks']; + } catch (Exception $e) { + // @todo log + $album->view_count = 0; + } + $album->created = $fields['clicks_date']; + $album->sort_column = 'weight'; //G1 was always sorted manually + $album->sort_order = 'ASC'; + } + + /** + * Set the highlight properly for a single album + */ + static function set_album_highlight(&$queue) { + $messages = array(); + if(count($queue)==0) { + $messages[] = t('Empty highlights queue'); + return $messages; + } + + $item = array_shift($queue); + if (substr($item, -10) == '.highlight') { + $item = substr($item, 0, strlen($item)-10); + } + g1_import::debug( t('Now importing highlight %item', array('item' => $item)) ); + + // Item names come in as Level:FolderX/ItemX + $pos = strpos($item, ':'); + if($pos===false) { + $messages[] = t('Invalid item %item', array('item' => $item)); + return $messages; + } + $item = substr($item, $pos+1); + + + // Item names come in as FolderX/ItemX + $pos = strrpos($item, '/'); + if($pos===false) { + $messages[] = t('Invalid item %item', array('item' => $item)); + return $messages; + } + + // Get ItemX into g1_item + $g1_item = substr($item,$pos+1); + // Get FolderX into g1_item + $g1_album = substr($item,0,$pos); + + + if (self::map($g1_album, '', 'highlight')) { + return $messages; + } + + $album_id = self::map($g1_album, '', 'album'); + if (!$album_id) { + $messages[] = t('Album %name not found', array('name' => $g1_album)); + return $messages; + } + + $item_id = self::map($g1_album, $g1_item, 'item'); + if (!$item_id) { + $item_id = self::map($g1_item, '', 'album'); + } + if (!$item_id) { + $messages[] = t('Item/Album %name not found', array('name' => $item)); + return $messages; + } + + $album = ORM::factory('item', $album_id); + $album->album_cover_item_id = $item_id; + $album->thumb_dirty = 1; + try { + $album->save(); + graphics::generate($album); + g1_import::debug( t('Added highlight %item to %album', array('item' => $item, 'album' => $album->name)) ); + } catch (Exception $e) { + $messages[] = (string) new G1_Import_Exception( + t("Failed to generate an album highlight for album '%name'.", + array('name' => $album->name)), + $e); + return $messages; + } + + $album_id = self::map($g1_album, '', 'album'); + self::set_map($album_id, $g1_album, '', 'highlight'); + + g1_import::debug( t('Added highlight %item to %album', array('item' => $item, 'album' => $album->name)) ); + return $messages; + } + + static function hotfix_all() { + $messages = array(); + $messages[] = t('Running Hotfix'); + + /* ON THE LAST RUN WE NEED TO RE-FIX ALL DAMAGED ALBUM THUMBS! */ + + $albumDir = self::$album_dir; + if(substr($albumDir,-1)!=DIRECTORY_SEPARATOR) $albumDir.=DIRECTORY_SEPARATOR; + + foreach(self::$albums_flat as $g1_album) { + $album_id = self::map($g1_album, '', 'album'); + if (!$album_id) { + $messages[] = t('Album %name not found', array('name' => $g1_album)); + continue; + } + + $album = ORM::factory('item', $album_id); + $importDir = $albumDir.$g1_album.DIRECTORY_SEPARATOR; + + try { + require_once('Gallery1DataParser.php'); + list($result, $items) = Gallery1DataParser::getPhotos($importDir); + if($result==null) + foreach($items as $object) { + if(isset($object->highlight) && $object->highlight==1 && isset($object->highlightImage) && is_a($object->highlightImage, 'G1Img')) { + $g1_path = $importDir.$object->highlightImage->name.'.'.$object->highlightImage->type; + if (is_file($g1_path) && @copy($g1_path, $album->thumb_path())) { + $album->thumb_height = $object->highlightImage->height; + $album->thumb_width = $object->highlightImage->width; + $album->thumb_dirty = false; + $album->save(); + } + } + } + } catch (Exception $e) { + $messages[] = (string) new G1_Import_Exception( + t('Failed to copy thumb for album %name.', + array('name' => $g1_album)), + $e); + } + } + + /* ON THE LAST RUN WE NEED TO RE-FIX ALL ALBUM PERMISSIONS */ + + foreach(self::$albums_hidden as $g1_album => $dummy) { + try { + $album_id = self::map($g1_album, '', 'album'); + $album = ORM::factory('item', $album_id); + access::deny(identity::everybody(), 'view', $album); + $messages[] = t('Denying access to %album', array('album' => $g1_album)); + } catch (Exception $e) { + $messages[] = (string) new G1_Import_Exception( + t('Failed to set access permission for hidden album %name.', + array('name' => $g1_album)), + $e); + } + } + + return $messages; + } + + /** + * Import a single photo or movie. + */ + static function import_item(&$queue) { + $messages = array(); + if(count($queue)==0) { + $messages[] = t('Empty item queue'); + return $messages; + } + + $item_id = array_shift($queue); + g1_import::debug( t('Now importing item %item', array('item' => $item_id)) ); + + // Item names come in as FolderX/ItemX + $pos = strrpos($item_id, '/'); + if($pos===false) { + return $messages; + } + + // Get ItemX into g1_item + $g1_item = substr($item_id,$pos+1); + // Get FolderX into g1_item + $g1_album = substr($item_id,0,$pos); + + + if (self::map($g1_album, $g1_item, 'item')) { + return $messages; + } + + $album_id = self::map($g1_album, '', 'album'); + if (!$album_id) { + $messages[] = t('Album %name not found', array('name' => $g1_album)); + return $messages; + } + + + $album_item = null; + + $albumDir = self::$album_dir; + if(substr($albumDir,-1)!=DIRECTORY_SEPARATOR) $albumDir.=DIRECTORY_SEPARATOR; + + require_once('Gallery1DataParser.php'); + list($result, $items) = Gallery1DataParser::getPhotos($albumDir.$g1_album.DIRECTORY_SEPARATOR); + if($result==null) + foreach($items as $object) { + if(isset($object->image) && is_a($object->image, 'G1Img') && isset($object->image->name) && ($object->image->name==$g1_item)) { + $album_item = $object; + } + } + + if ($album_item==null) { + $messages[] = t('Failed to import Gallery 1 item: %item', array('item' => $item_id)); + return $messages; + } + + $corrupt = 0; + self::$current_g1_item = array( $item_id => $album_item ); + $g1_path = $albumDir.$g1_album.DIRECTORY_SEPARATOR.$album_item->image->name.'.'.$album_item->image->type; + + $parent = ORM::factory('item', $album_id); + + switch($album_item->image->type) { + case 'jpg': + case 'jpeg': + case 'gif': + case 'png': + $g1_type = 'GalleryPhotoItem'; break; + case 'wmv': + case '3gp': + case 'avi': + case 'mp4': + case 'flv': + $g1_type = 'GalleryMovieItem'; break; + default: + $g1_type = 'GalleryPhotoItem'; break; + } + + if (!file_exists($g1_path)) { + // If the Gallery 1 source image isn't available, this operation is going to fail. That can + // happen in cases where there's corruption in the source Gallery 1. In that case, fall + // back on using a broken image. It's important that we import *something* otherwise + // anything that refers to this item in Gallery 1 will have a dangling pointer in Gallery 3 + // + // Note that this will change movies to be photos, if there's a broken movie. Hopefully + // this case is rare enough that we don't need to take any heroic action here. + g1_import::log( + t('%path missing in import; replacing it with a placeholder', array('path' => $g1_path))); + $g1_path = MODPATH . 'g1_import/data/broken-image.gif'; + $g1_type = 'GalleryPhotoItem'; + $corrupt = 1; + } + + $item = null; + + switch ($g1_type) { + case 'GalleryPhotoItem': + + if(function_exists('mime_content_type')) + $type = mime_content_type($g1_path); + else + $type = self::get_mime_type($g1_path); + + if ($type!='' && !in_array($type, array('image/jpeg', 'image/gif', 'image/png'))) { + Kohana_Log::add('alert', "$g1_path is an unsupported image type $type; using a placeholder gif"); + $messages[] = t("'%path' is an unsupported image type '%type', using a placeholder", + array('path' => $g1_path, 'type' => $type)); + $g1_path = MODPATH . 'g1_import/data/broken-image.gif'; + $corrupt = 1; + } + + try { + $item = ORM::factory('item'); + $item->type = 'photo'; + $item->parent_id = $album_id; + $item->set_data_file($g1_path); + $item->name = $g1_item.'.'.$album_item->image->type; + $item->slug = $g1_item; + $item->mime_type = $type; + $item->title = utf8_encode(self::_decode_html_special_chars(trim($album_item->caption))); + $item->title or $item->title = ' '; //don't use $item->name as this clutters up the UI + if(isset($album_item->description) && $album_item->description!='') + $item->description = utf8_encode(self::_decode_html_special_chars(trim($album_item->description))); + //$item->owner_id = self::map($g1_item->getOwnerId()); + try { + $item->view_count = (int) $album_item->clicks; + } catch (Exception $e) { + $view_count = 1; + } + } catch (Exception $e) { + $exception_info = (string) new G1_Import_Exception( + t("Corrupt image '%path'", array('path' => $g1_path)), + $e, $messages); + Kohana_Log::add('alert', "Corrupt image $g1_path\n" . $exception_info); + $messages[] = $exception_info; + $corrupt = 1; + $item = null; + return $messages; + } + + try { + $item->validate(); + } catch (ORM_Validation_Exception $e) { + $exception_info = (string) new G1_Import_Exception( + t('Failed to validate Gallery 1 item %item.', + array('item' => $item_id)), + $e, $messages); + Kohana_Log::add('alert', "Failed to validate Gallery 1 item $item_id.\n" . $exception_info); + $messages[] = $exception_info; + $corrupt = 1; + $item = null; + return $messages; + } + + try { + $item->save(); + } catch (Exception $e) { + $exception_info = (string) new G1_Import_Exception( + t('Failed to import Gallery 1 item %item.', + array('item' => $item_id)), + $e, $messages); + Kohana_Log::add('alert', "Failed to import Gallery 1 item $item_id.\n" . $exception_info); + $messages[] = $exception_info; + $corrupt = 1; + $item = null; + } + + break; + + case 'GalleryMovieItem': + // @todo we should transcode other types into FLV + + if(function_exists('mime_content_type')) + $type = mime_content_type($g1_path); + else + $type = self::get_mime_type($g1_path); + + if ($type=='' || in_array($type, array('video/mp4', 'video/x-flv'))) { + try { + $item = ORM::factory('item'); + $item->type = 'movie'; + $item->parent_id = $album_id; + $item->set_data_file($g1_path); + $item->name = $g1_item.'.'.$album_item->image->type; + $item->slug = $g1_item; + $item->mime_type = $type; + $item->title = utf8_encode(self::_decode_html_special_chars(trim($album_item->caption))); + $item->title or $item->title = ' '; //$item->name; + if(isset($album_item->description) && $album_item->description!='') + $item->description = utf8_encode(self::_decode_html_special_chars(trim($album_item->description))); + //$item->owner_id = self::map($g1_item->getOwnerId()); + try { + $item->view_count = (int) $album_item->clicks; + } catch (Exception $e) { + $view_count = 1; + } + } catch (Exception $e) { + $exception_info = (string) new G1_Import_Exception( + t("Corrupt movie '%path'", array("path" => $g1_path)), + $e, $messages); + Kohana_Log::add('alert', "Corrupt movie $g1_path\n" . $exception_info); + $messages[] = $exception_info; + $corrupt = 1; + $item = null; + return $messages; + } + + try { + $item->validate(); + } catch (ORM_Validation_Exception $e) { + $exception_info = (string) new G1_Import_Exception( + t('Failed to validate Gallery 1 item %item.', + array('item' => $item_id)), + $e, $messages); + Kohana_Log::add('alert', "Failed to validate Gallery 1 item $item_id.\n" . $exception_info); + $messages[] = $exception_info; + $corrupt = 1; + $item = null; + return $messages; + } + + try { + $item->save(); + } catch (Exception $e) { + $exception_info = (string) new G1_Import_Exception( + t('Failed to import Gallery 1 item %item.', + array('item' => $item_id)), + $e, $messages); + Kohana_Log::add('alert', "Failed to import Gallery 1 item $item_id.\n" . $exception_info); + $messages[] = $exception_info; + $corrupt = 1; + $item = null; + } + } else { + Kohana_Log::add('alert', "$g1_path is an unsupported movie type $type"); + $messages[] = t("'%path' is an unsupported movie type '%type'", array('path' => $g1_path, 'type' => $type)); + $corrupt = 1; + } + + break; + + default: + // Ignore + break; + } + + if (isset($item)) { + self::set_map($item->id, $g1_album, $g1_item, 'item'); + + if(isset($album_item->keywords) && $album_item->keywords!='') { + $keywords = utf8_encode(self::_decode_html_special_chars(trim($album_item->keywords))); + if($keywords!='') { + self::import_keywords_as_tags($keywords, $item); + } + } + } + + if ($corrupt) { + $title = utf8_encode(self::_decode_html_special_chars(trim($album_item->caption))); + $title or $title = $g1_item; + if (!empty($item)) { + $messages[] = + t('%title from Gallery 1 could not be processed; (imported as %title)', + array('g1_url' => $gallery_url.'/'.$item_id, + 'g3_url' => $item->url(), + 'title' => $title)); + } else { + $messages[] = + t('%title from Gallery 1 could not be processed', + array('g1_url' => $gallery_url.'/'.$item_id, 'title' => $title)); + } + } + + self::$current_g1_item = null; + return $messages; + } + + function get_mime_type($filename, $mimePath = '/etc') { + $fileext = substr(strrchr($filename, '.'), 1); + if (empty($fileext)) return (false); + $regex = "/^([\w\+\-\.\/]+)\s+(\w+\s)*($fileext\s)/i"; + $lines = file("$mimePath/mime.types"); + foreach($lines as $line) { + if (substr($line, 0, 1) == '#') continue; // skip comments + $line = rtrim($line) . ' '; + if (!preg_match($regex, $line, $matches)) continue; // no match to the extension + return ($matches[1]); + } + return (false); // no match at all + } + + /** + * Import a single comment. + */ + static function import_comment(&$queue) { + $messages = array(); + if(count($queue)==0) { + //this case happens if more than one comment is found on one or more items + $messages[] = t('Empty comments queue'); + return $messages; + } + + $element = array_shift($queue); + + list($item, $comments) = each($element); + g1_import::debug( t('Now importing %$comments comment(s) for item %$item', array('album' => $item, 'comments' => count($comments))) ); + + // Item names come in as FolderX/ItemX + $pos = strrpos($item, '/'); + if($pos===false) { + $messages[] = t('Invalid item %item', array('item' => $item)); + return $messages; + } + + // Get ItemX into g1_item + $g1_item = substr($item,$pos+1); + // Get FolderX into g1_item + $g1_album = substr($item,0,$pos); + + + if (self::map($g1_album, $g1_item, 'comment')) { + return $messages; + } + + $item_id = self::map($g1_album, $g1_item, 'item'); + if (empty($item_id)) { + $messages[] = t('Could not find item %item', array('item' => $item)); + return; + } + + foreach ($comments as $g1comment) { + + // Just import the fields we know about. Do this outside of the comment API for now so that + // we don't trigger spam filtering events + $comment = ORM::factory('comment'); + $comment->author_id = identity::guest()->id; + $comment->guest_name = utf8_encode(self::_decode_html_special_chars(trim($g1comment['name']))); + $comment->guest_name or $comment->guest_name = (string) t('Anonymous coward'); + $comment->guest_email = 'unknown@nobody.com'; + $comment->item_id = $item_id; + $comment->text = utf8_encode(self::_decode_html_special_chars(trim($g1comment['commentText']))); + $comment->state = 'published'; + $comment->server_http_host = utf8_encode(self::_decode_html_special_chars(trim($g1comment['IPNumber']))); + + try { + $comment->save(); + } catch (Exception $e) { + $messages[] = (string) new G1_Import_Exception( + t('Failed to import comment for item: %item.', + array('item' => $item)), + $e); + return $messages; + } + + // Backdate the creation date. We can't do this at creation time because + // Comment_Model::save() will override it. + db::update('comments') + ->set('created', utf8_encode(self::_decode_html_special_chars(trim($g1comment['datePosted'])))) + ->set('updated', utf8_encode(self::_decode_html_special_chars(trim($g1comment['datePosted'])))) + ->where('id', '=', $comment->id) + ->execute(); + } + + self::set_map($item_id, $g1_album, $g1_item, 'comment'); + return $messages; + } + + /** + * g1 encoded'&', '"', '<' and '>' as '&', '"', '<' and '>' respectively. + * This function undoes that encoding. + */ + private static function _decode_html_special_chars($value) { + return str_replace(array('&', '"', '<', '>', 'ä', 'ö', 'ü', 'Ä', 'Ö', 'Ü', 'ß'), + array('&', '"', '<', '>', 'ä', 'ö', 'ü', 'Ä', 'Ö', 'Ü', 'ß'), $value); + } + + static function import_keywords_as_tags($keywords, $item) { + // FIXME check if this is true for G1 (copied from G2 import module): + // Keywords in G1 are free form. So we don't know what our user used as a separator. Try to + // be smart about it. If we see a comma or a semicolon, expect the keywords to be separated + // by that delimeter. Otherwise, use space as the delimiter. + if (strpos($keywords, ';')) { + $delim = ';'; + } else if (strpos($keywords, ',')) { + $delim = ','; + } else { + $delim = ' '; + } + + foreach (preg_split("/$delim/", $keywords) as $keyword) { + $keyword = trim($keyword); + if ($keyword) { + tag::add($item, $keyword); + } + } + } + + /** + * If the thumbnails and resizes created for the Gallery 1 photo match the dimensions of the + * ones we expect to create for Gallery 3, then copy the files over instead of recreating them. + */ + static function copy_matching_thumbnails_and_resizes($item) { + + // We only operate on items that are being imported + if (empty(self::$current_g1_item)) { + return; + } + + // Precaution: if the Gallery 1 item was watermarked, or we have the Gallery 3 watermark module + // active then we'd have to do something a lot more sophisticated here. For now, just skip + // this step in those cases. + // @todo we should probably use an API here, eventually. + if (module::is_active('watermark') && module::get_var('watermark', 'name')) { + return; + } + + // For now just do the copy for photos and movies. Albums are tricky because we're may not + // yet be setting their album cover properly. + // @todo implement this for albums also + if (!$item->is_movie() && !$item->is_photo()) { + return; + } + + list( $item_id, $album_item ) = each(self::$current_g1_item); + + // Item names come in as FolderX/ItemX + $pos = strrpos($item_id, '/'); + if($pos===false) { + return; + } + + // Get ItemX into g1_item + $g1_item = substr($item_id,$pos+1); + // Get FolderX into g1_item + $g1_album = substr($item_id,0,$pos); + + + $target_thumb_size = module::get_var('gallery', 'thumb_size'); + $target_resize_size = module::get_var('gallery', 'resize_size'); + if ( isset($album_item->thumbnail) && is_a($album_item->thumbnail, 'G1Img') ) { + + if($item->thumb_dirty && + ($album_item->thumbnail->width == $target_thumb_size || + $album_item->thumbnail->height == $target_thumb_size)) { + + $g1_path = $albumDir.$g1_album.DIRECTORY_SEPARATOR.$album_item->thumbnail->name.'.'.$album_item->thumbnail->type; + if (@copy($g1_path, $item->thumb_path())) { + $item->thumb_height = $album_item->thumbnail->height; + $item->thumb_width = $album_item->thumbnail->width; + $item->thumb_dirty = false; + } + /** + * No use to try to take over the highlight images here as they will be overwritten anyway. + */ + } + } + + try { + $item->save(); + } catch (Exception $e) { + return (string) new G1_Import_Exception( + t("Failed to copy thumbnails and resizes for item '%name' (Gallery 1 id: %id)", + array('name' => $item->name, 'id' => $item_id)), + $e); + } + } + + /** + * Figure out the most common resize and thumb sizes in Gallery 1 so that we can tell the admin + * what theme settings to set to make the import go faster. If we match up the sizes then we + * can just copy over derivatives instead of running graphics toolkit operations. + */ + static function common_sizes() { + return array( 'resize' => array( 'size' => self::$resize_size, 'count' => 1 ) + ,'thumb' => array( 'size' => self::$thumb_size, 'count' => 1 ) + ,'total' => 1 + ); + } + + /** + * Look in our map to find the corresponding Gallery 3 id for the given Gallery 1 id. + */ + static function map($album, $item, $resource_type) { + if (!array_key_exists($resource_type.':'.$album.'/'.$item, self::$map)) { + $mapping = ORM::factory('g1_map')->where('album', '=', $album)->where('item', '=', $item)->where('resource_type', '=', $resource_type)->find(); + self::$map[$resource_type.':'.$album.'/'.$item] = $mapping->loaded() ? $mapping->id : null; + } + + return self::$map[$resource_type.':'.$album.'/'.$item]; + } + + /** + * Associate a Gallery 1 id with a Gallery 3 item id. + */ + static function set_map($id, $album, $item, $resource_type) { + $mapping = ORM::factory('g1_map'); + $mapping->id = $id; + $mapping->album = $album; + $mapping->item = $item; + $mapping->resource_type = $resource_type; + $mapping->save(); + self::$map[$resource_type.':'.$album.'/'.$item] = $id; + } + + static function log($msg) { + message::warning($msg); + Kohana_Log::add('alert', $msg); + } + + static function debug($msg) { + Kohana_Log::add('debug', $msg); + } +} diff --git a/3.0/modules/g1_import/helpers/g1_import_event.php b/3.0/modules/g1_import/helpers/g1_import_event.php new file mode 100644 index 00000000..4204f4d7 --- /dev/null +++ b/3.0/modules/g1_import/helpers/g1_import_event.php @@ -0,0 +1,40 @@ +delete("g1_maps") + ->where("id", "=", $item->id) + ->execute(); + } + + static function item_created($item) { + g1_import::copy_matching_thumbnails_and_resizes($item); + } + + static function admin_menu($menu, $theme) { + $menu + ->get("settings_menu") + ->append(Menu::factory("link") + ->id("g1_import") + ->label(t("Gallery 1 import")) + ->url(url::site("admin/g1_import"))); + } +} diff --git a/3.0/modules/g1_import/helpers/g1_import_installer.php b/3.0/modules/g1_import/helpers/g1_import_installer.php new file mode 100644 index 00000000..fb1ea1f5 --- /dev/null +++ b/3.0/modules/g1_import/helpers/g1_import_installer.php @@ -0,0 +1,46 @@ +query("CREATE TABLE IF NOT EXISTS {g1_maps} ( + `id` int(9) NOT NULL, + `album` varchar(128) NOT NULL, + `item` varchar(128) default NULL, + `resource_type` varchar(64) default NULL, + PRIMARY KEY (`id`, `resource_type`), + KEY `g1_map_index` (`album`, `item`)) + DEFAULT CHARSET=utf8;"); + + module::set_version("g1_import", 1); + } + + static function upgrade($version) { + $db = Database::instance(); + /* reserved for future versions + if ($version == 1) { + module::set_version('g1_import', $version = 2); + } + //*/ + } + + static function uninstall() { + } +} diff --git a/3.0/modules/g1_import/helpers/g1_import_task.php b/3.0/modules/g1_import/helpers/g1_import_task.php new file mode 100644 index 00000000..32edd3cc --- /dev/null +++ b/3.0/modules/g1_import/helpers/g1_import_task.php @@ -0,0 +1,215 @@ +callback('g1_import_task::import') + ->name(t('Import from Gallery 1')) + ->description( + t('Gallery %version detected', array('version' => $version))) + ->severity(log::SUCCESS)); + } + + return array(); + } + + static function import($task) { + $start = microtime(true); + g1_import::init(); + + $stats = $task->get('stats'); + $done = $task->get('done'); + $total = $task->get('total'); + $completed = $task->get('completed'); + $mode = $task->get('mode'); + $queue = $task->get('queue'); + if (!isset($mode)) { + $stats = g1_import::g1_stats(); + $stats['items'] = $stats['photos'] + $stats['movies']; + unset($stats['photos']); + unset($stats['movies']); + $stats['fix'] = 1; + $task->set('stats', $stats); + + $task->set('total', $total = array_sum(array_values($stats))); + $completed = 0; + $mode = 0; + + $done = array(); + foreach (array_keys($stats) as $key) { + $done[$key] = 0; + } + $task->set('done', $done); + } + + $modes = array('users', 'albums', 'items', 'comments', 'highlights', 'fix', 'done'); + while (!$task->done && microtime(true) - $start < 1.5) { + if ($done[$modes[$mode]] >= $stats[$modes[$mode]]) { + // Nothing left to do for this mode. Advance. + $mode++; + $task->set('last_id', 0); + $queue = array(); + + // Start the loop from the beginning again. This way if we get to a mode that requires no + // actions (eg, if the G1 comments module isn't installed) we won't try to do any comments + // queries.. in the next iteration we'll just skip over that mode. + if ($modes[$mode] != 'done') { + continue; + } + } + + switch($modes[$mode]) { + + case 'users': + $done['users'] = $stats['users']-1; + $task->status = t( + 'Ignoring users (%count of %total)', + array('count' => $done['users'], 'total' => $stats['users'])); + break; + + case 'albums': + if (empty($queue)) { + if(count(g1_import::$tree)==0) { + g1_import::g1_stats(); + } + $task->set('queue', $queue = array('' => g1_import::$tree)); + } + $log_message = g1_import::import_album($queue); + if ($log_message) { + $task->log($log_message); + } + $task->status = t( + 'Importing albums (%count of %total)', + array('count' => $done['albums'] + 1, 'total' => $stats['albums'])); + break; + + case 'items': + if (empty($queue)) { + if (count(g1_import::$queued_items)==0) { + g1_import::g1_stats(); + } + + $queuelen = 100; + $thisstart = $task->get('last_id', 0); + $nextstart = $thisstart + $queuelen; + $task->set('last_id', $nextstart); + + $task->set('queue', $queue = array_splice(g1_import::$queued_items, $thisstart, $queuelen)); + } + $log_message = g1_import::import_item($queue); + if ($log_message) { + $task->log($log_message); + } + $task->status = t( + 'Importing photos (%count of %total)', + array('count' => $done['items'] + 1, 'total' => $stats['items'])); + break; + + case 'comments': + if (empty($queue)) { + if (count(g1_import::$queued_comments)==0) { + g1_import::g1_stats(); + } + + $queuelen = 100; + $thisstart = $task->get('last_id', 0); + $nextstart = $thisstart + $queuelen; + $task->set('last_id', $nextstart); + + $task->set('queue', $queue = array_splice(g1_import::$queued_comments, $thisstart, $queuelen)); + } + $log_message = g1_import::import_comment($queue); + if ($log_message) { + $task->log($log_message); + } + $task->status = t( + 'Importing comments (%count of %total)', + array('count' => $done['comments'] + 1, 'total' => $stats['comments'])); + break; + + case 'highlights': + if (empty($queue)) { + if (count(g1_import::$queued_highlights)==0) { + g1_import::g1_stats(); + } + + $queuelen = 100; + $thisstart = $task->get('last_id', 0); + $nextstart = $thisstart + $queuelen; + $task->set('last_id', $nextstart); + + $task->set('queue', $queue = array_splice(g1_import::$queued_highlights, $thisstart, $queuelen)); + } + $log_message = g1_import::set_album_highlight($queue); + if ($log_message) { + $task->log($log_message); + } + $task->status = t( + 'Album highlights (%count of %total)', + array('count' => $done['highlights'] + 1, 'total' => $stats['highlights'])); + break; + + case 'fix': + if (empty($queue)) { + if (count(g1_import::$albums_flat)==0) { + g1_import::g1_stats(); + } + $task->set('queue', $queue = 'dummy'); + } + $log_message = g1_import::hotfix_all(); + if ($log_message) { + $task->log($log_message); + } + $task->status = t( + 'Final Hotfixing (%count of %total)', + array('count' => $done['fix'] + 1, 'total' => $stats['fix'])); + break; + + case 'done': + $task->status = t('Import complete'); + $task->done = true; + $task->state = 'success'; + break; + } + + if (!$task->done) { + $done[$modes[$mode]]++; + $completed++; + } + } + + $task->percent_complete = 100 * ($completed / $total); + $task->set('completed', $completed); + $task->set('mode', $mode); + $task->set('queue', $queue); + $task->set('done', $done); + } +} diff --git a/3.0/modules/g1_import/libraries/G1_Import_Exception.php b/3.0/modules/g1_import/libraries/G1_Import_Exception.php new file mode 100644 index 00000000..cd7e476f --- /dev/null +++ b/3.0/modules/g1_import/libraries/G1_Import_Exception.php @@ -0,0 +1,39 @@ +validation->errors(), true); + } + if ($previous) { + $message .= "\n" . (string) $previous; + } + // The $previous parameter is supported in PHP 5.3.0+. + parent::__construct($message); + } +} \ No newline at end of file diff --git a/3.0/modules/g1_import/models/g1_map.php b/3.0/modules/g1_import/models/g1_map.php new file mode 100644 index 00000000..b783426d --- /dev/null +++ b/3.0/modules/g1_import/models/g1_map.php @@ -0,0 +1,21 @@ + +css("jquery.autocomplete.css") ?> +script("jquery.autocomplete.js") ?> + + +
+

+

+ +

+ + + +