From 4a9a5076ff08ef441e28cd3b87e8e9502478b6e5 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 29 Dec 2010 13:51:59 -0800 Subject: [PATCH] Web UI for importing delicious backup files --- plugins/Bookmark/BookmarkPlugin.php | 14 ++ plugins/Bookmark/importdelicious.php | 309 +++++++++++++++++++++++++++ 2 files changed, 323 insertions(+) create mode 100644 plugins/Bookmark/importdelicious.php diff --git a/plugins/Bookmark/BookmarkPlugin.php b/plugins/Bookmark/BookmarkPlugin.php index d93f61c81d..a714adc984 100644 --- a/plugins/Bookmark/BookmarkPlugin.php +++ b/plugins/Bookmark/BookmarkPlugin.php @@ -47,6 +47,16 @@ if (!defined('STATUSNET')) { class BookmarkPlugin extends Plugin { const VERSION = '0.1'; + const IMPORTDELICIOUS = 'BookmarkPlugin:IMPORTDELICIOUS'; + + function onUserRightsCheck($profile, $right, &$result) + { + if ($right == self::IMPORTDELICIOUS) { + $result = !$profile->isSilenced(); + return false; + } + return true; + } /** * Database schema setup @@ -158,6 +168,7 @@ class BookmarkPlugin extends Plugin case 'NewbookmarkAction': case 'BookmarkpopupAction': case 'NoticebyurlAction': + case 'ImportdeliciousAction': include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php'; return false; case 'Bookmark': @@ -190,6 +201,9 @@ class BookmarkPlugin extends Plugin $m->connect('main/bookmark/popup', array('action' => 'bookmarkpopup')); + $m->connect('main/bookmark/import', + array('action' => 'importdelicious')); + $m->connect('bookmark/:user/:created/:crc32', array('action' => 'showbookmark'), array('user' => '[0-9]+', diff --git a/plugins/Bookmark/importdelicious.php b/plugins/Bookmark/importdelicious.php new file mode 100644 index 0000000000..52f532bf5a --- /dev/null +++ b/plugins/Bookmark/importdelicious.php @@ -0,0 +1,309 @@ +. + * + * @category Bookmark + * @package StatusNet + * @author Evan Prodromou + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + // This check helps protect against security problems; + // your code file can't be executed directly from the web. + exit(1); +} + +/** + * UI for importing del.icio.us bookmark backups + * + * @category Bookmark + * @package StatusNet + * @author Evan Prodromou + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +class ImportdeliciousAction extends Action +{ + protected $success = false; + + function title() + { + return _("Import del.icio.us bookmarks"); + } + + /** + * For initializing members of the class. + * + * @param array $argarray misc. arguments + * + * @return boolean true + */ + + function prepare($argarray) + { + parent::prepare($argarray); + + $cur = common_current_user(); + + if (empty($cur)) { + throw new ClientException(_('Only logged-in users can import del.icio.us backups.'), 403); + } + + if (!$cur->hasRight(BookmarkPlugin::IMPORTDELICIOUS)) { + throw new ClientException(_('You may not restore your account.'), 403); + } + + return true; + } + + /** + * Handler method + * + * @param array $argarray is ignored since it's now passed in in prepare() + * + * @return void + */ + + function handle($argarray=null) + { + parent::handle($argarray); + + if ($this->isPost()) { + $this->importDelicious(); + } else { + $this->showPage(); + } + return; + } + + /** + * Queue a file for importation + * + * Uses the DeliciousBackupImporter class; may take a long time! + * + * @return void + */ + + function importDelicious() + { + $this->checkSessionToken(); + + if (!isset($_FILES[ImportDeliciousForm::FILEINPUT]['error'])) { + throw new ClientException(_('No uploaded file.')); + } + + switch ($_FILES[ImportDeliciousForm::FILEINPUT]['error']) { + case UPLOAD_ERR_OK: // success, jump out + break; + case UPLOAD_ERR_INI_SIZE: + // TRANS: Client exception thrown when an uploaded file is larger than set in php.ini. + throw new ClientException(_('The uploaded file exceeds the ' . + 'upload_max_filesize directive in php.ini.')); + return; + case UPLOAD_ERR_FORM_SIZE: + throw new ClientException( + // TRANS: Client exception. + _('The uploaded file exceeds the MAX_FILE_SIZE directive' . + ' that was specified in the HTML form.')); + return; + case UPLOAD_ERR_PARTIAL: + @unlink($_FILES[ImportDeliciousForm::FILEINPUT]['tmp_name']); + // TRANS: Client exception. + throw new ClientException(_('The uploaded file was only' . + ' partially uploaded.')); + return; + case UPLOAD_ERR_NO_FILE: + // No file; probably just a non-AJAX submission. + throw new ClientException(_('No uploaded file.')); + return; + case UPLOAD_ERR_NO_TMP_DIR: + // TRANS: Client exception thrown when a temporary folder is not present to store a file upload. + throw new ClientException(_('Missing a temporary folder.')); + return; + case UPLOAD_ERR_CANT_WRITE: + // TRANS: Client exception thrown when writing to disk is not possible during a file upload operation. + throw new ClientException(_('Failed to write file to disk.')); + return; + case UPLOAD_ERR_EXTENSION: + // TRANS: Client exception thrown when a file upload operation has been stopped by an extension. + throw new ClientException(_('File upload stopped by extension.')); + return; + default: + common_log(LOG_ERR, __METHOD__ . ": Unknown upload error " . + $_FILES[ImportDeliciousForm::FILEINPUT]['error']); + // TRANS: Client exception thrown when a file upload operation has failed with an unknown reason. + throw new ClientException(_('System error uploading file.')); + return; + } + + $filename = $_FILES[ImportDeliciousForm::FILEINPUT]['tmp_name']; + + try { + if (!file_exists($filename)) { + throw new ServerException("No such file '$filename'."); + } + + if (!is_file($filename)) { + throw new ServerException("Not a regular file: '$filename'."); + } + + if (!is_readable($filename)) { + throw new ServerException("File '$filename' not readable."); + } + + common_debug(sprintf(_("Getting backup from file '%s'."), $filename)); + + $html = file_get_contents($filename); + + // Enqueue for processing. + + $qm = QueueManager::get(); + $qm->enqueue(array(common_current_user(), $html), 'dlcsback'); + + $this->success = true; + + $this->showPage(); + + } catch (Exception $e) { + // Delete the file and re-throw + @unlink($_FILES[ImportDeliciousForm::FILEINPUT]['tmp_name']); + throw $e; + } + } + + function showContent() + { + if ($this->success) { + $this->element('p', null, + _('Feed will be restored. Please wait a few minutes for results.')); + } else { + $form = new ImportDeliciousForm($this); + $form->show(); + } + } + + /** + * Return true if read only. + * + * MAY override + * + * @param array $args other arguments + * + * @return boolean is read only action? + */ + + function isReadOnly($args) + { + return !$this->isPost(); + } +} + +/** + * A form for backing up the account. + * + * @category Account + * @package StatusNet + * @author Evan Prodromou + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +class ImportDeliciousForm extends Form +{ + const FILEINPUT = 'deliciousbackupfile'; + + function __construct($out=null) { + parent::__construct($out); + $this->enctype = 'multipart/form-data'; + } + + /** + * Class of the form. + * + * @return string the form's class + */ + + function formClass() + { + return 'form_import_delicious'; + } + + /** + * URL the form posts to + * + * @return string the form's action URL + */ + + function action() + { + return common_local_url('importdelicious'); + } + + /** + * Output form data + * + * Really, just instructions for doing a backup. + * + * @return void + */ + + function formData() + { + $this->out->elementStart('p', 'instructions'); + + $this->out->raw(_('You can upload a backed-up delicious.com bookmarks file.')); + + $this->out->elementEnd('p'); + + $this->out->elementStart('ul', 'form_data'); + + $this->out->elementStart('li', array ('id' => 'settings_attach')); + $this->out->element('input', array('name' => self::FILEINPUT, + 'type' => 'file', + 'id' => self::FILEINPUT)); + $this->out->elementEnd('li'); + + $this->out->elementEnd('ul'); + } + + /** + * Buttons for the form + * + * In this case, a single submit button + * + * @return void + */ + + function formActions() + { + $this->out->submit('submit', + _m('BUTTON', 'Upload'), + 'submit', + null, + _('Upload the file')); + } +}