public function importEventsFromSource(PhabricatorUser $viewer, PhabricatorCalendarImport $import, $should_queue) { $uri_key = PhabricatorCalendarImportICSURITransaction::PARAMKEY_URI; $uri = $import->getParameter($uri_key); PhabricatorSystemActionEngine::willTakeAction(array($viewer->getPHID()), new PhabricatorFilesOutboundRequestAction(), 1); $file = PhabricatorFile::newFromFileDownload($uri, array('viewPolicy' => PhabricatorPolicies::POLICY_NOONE, 'authorPHID' => $import->getAuthorPHID(), 'canCDN' => true)); $import->newLogMessage(PhabricatorCalendarImportFetchLogType::LOGTYPE, array('file.phid' => $file->getPHID())); $data = $file->loadFileData(); if ($should_queue && $this->shouldQueueDataImport($data)) { return $this->queueDataImport($import, $data); } return $this->importICSData($viewer, $import, $data); }
public function importEventsFromSource(PhabricatorUser $viewer, PhabricatorCalendarImport $import, $should_queue) { $phid_key = PhabricatorCalendarImportICSFileTransaction::PARAMKEY_FILE; $file_phid = $import->getParameter($phid_key); $file = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs(array($file_phid))->executeOne(); if (!$file) { throw new Exception(pht('Unable to load file ("%s") for import.', $file_phid)); } $data = $file->loadFileData(); if ($should_queue && $this->shouldQueueDataImport($data)) { return $this->queueDataImport($import, $data); } return $this->importICSData($viewer, $import, $data); }
protected final function importICSData(PhabricatorUser $viewer, PhabricatorCalendarImport $import, $data) { $parser = new PhutilICSParser(); try { $document = $parser->parseICSData($data); } catch (PhutilICSParserException $ex) { // TODO: In theory, it would be nice to store these in a fully abstract // form so they can be translated at display time. As-is, we'll store the // error messages in whatever language we were using when the parser // failure occurred. $import->newLogMessage(PhabricatorCalendarImportICSLogType::LOGTYPE, array('ics.code' => $ex->getParserFailureCode(), 'ics.message' => $ex->getMessage())); $document = null; } foreach ($parser->getWarnings() as $warning) { $import->newLogMessage(PhabricatorCalendarImportICSWarningLogType::LOGTYPE, array('ics.warning.code' => $warning['code'], 'ics.warning.line' => $warning['line'], 'ics.warning.text' => $warning['text'], 'ics.warning.message' => $warning['message'])); } return $this->importEventDocument($viewer, $import, $document); }
public function validateTransactions($object, array $xactions) { $errors = array(); $frequency_map = PhabricatorCalendarImport::getTriggerFrequencyMap(); $valid = array_keys($frequency_map); $valid = array_fuse($valid); foreach ($xactions as $xaction) { $value = $xaction->getNewValue(); if (!isset($valid[$value])) { $errors[] = $this->newInvalidError(pht('Import frequency "%s" is not valid. Valid frequences are: %s.', $value, implode(', ', $valid)), $xaction); } } return $errors; }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); if (!$request->validateCSRF()) { return new Aphront400Response(); } $cancel_uri = $this->getApplicationURI(); $ids = $request->getStrList('h'); if ($ids) { $files = id(new PhabricatorFileQuery())->setViewer($viewer)->withIDs($ids)->setRaisePolicyExceptions(true)->execute(); } else { $files = array(); } if (!$files) { return $this->newDialog()->setTitle(pht('Nothing Uploaded'))->appendParagraph(pht('Drag and drop .ics files to upload them and import them into ' . 'Calendar.'))->addCancelButton($cancel_uri, pht('Done')); } $engine = new PhabricatorCalendarICSFileImportEngine(); $imports = array(); foreach ($files as $file) { $import = PhabricatorCalendarImport::initializeNewCalendarImport($viewer, clone $engine); $xactions = array(); $xactions[] = id(new PhabricatorCalendarImportTransaction())->setTransactionType(PhabricatorCalendarImportICSFileTransaction::TRANSACTIONTYPE)->setNewValue($file->getPHID()); $editor = id(new PhabricatorCalendarImportEditor())->setActor($viewer)->setContinueOnNoEffect(true)->setContinueOnMissingFields(true)->setContentSourceFromRequest($request); $editor->applyTransactions($import, $xactions); $imports[] = $import; } $import_phids = mpull($imports, 'getPHID'); $events = id(new PhabricatorCalendarEventQuery())->setViewer($viewer)->withImportSourcePHIDs($import_phids)->execute(); if (count($events) == 1) { // The user imported exactly one event. This is consistent with dropping // a .ics file from an email; just take them to the event. $event = head($events); $next_uri = $event->getURI(); } else { if (count($imports) > 1) { // The user imported multiple different files. Take them to a summary // list of generated import activity. $source_phids = implode(',', $import_phids); $next_uri = '/calendar/import/log/?importSourcePHIDs=' . $source_phids; } else { // The user imported one file, which had zero or more than one event. // Take them to the import detail page. $import = head($imports); $next_uri = $import->getURI(); } } return id(new AphrontRedirectResponse())->setURI($next_uri); }
protected function buildCustomEditFields($object) { $viewer = $this->getViewer(); $engine = $object->getEngine(); $can_trigger = $engine->supportsTriggers($object); $fields = array(id(new PhabricatorTextEditField())->setKey('name')->setLabel(pht('Name'))->setDescription(pht('Name of the import.'))->setTransactionType(PhabricatorCalendarImportNameTransaction::TRANSACTIONTYPE)->setConduitDescription(pht('Rename the import.'))->setConduitTypeDescription(pht('New import name.'))->setPlaceholder($object->getDisplayName())->setValue($object->getName()), id(new PhabricatorBoolEditField())->setKey('disabled')->setOptions(pht('Active'), pht('Disabled'))->setLabel(pht('Disabled'))->setDescription(pht('Disable the import.'))->setTransactionType(PhabricatorCalendarImportDisableTransaction::TRANSACTIONTYPE)->setIsConduitOnly(true)->setConduitDescription(pht('Disable or restore the import.'))->setConduitTypeDescription(pht('True to cancel the import.'))->setValue($object->getIsDisabled()), id(new PhabricatorBoolEditField())->setKey('delete')->setLabel(pht('Delete Imported Events'))->setDescription(pht('Delete all events from this source.'))->setTransactionType(PhabricatorCalendarImportDisableTransaction::TRANSACTIONTYPE)->setIsConduitOnly(true)->setConduitDescription(pht('Disable or restore the import.'))->setConduitTypeDescription(pht('True to delete imported events.'))->setValue(false), id(new PhabricatorBoolEditField())->setKey('reload')->setLabel(pht('Reload Import'))->setDescription(pht('Reload events imported from this source.'))->setTransactionType(PhabricatorCalendarImportDisableTransaction::TRANSACTIONTYPE)->setIsConduitOnly(true)->setConduitDescription(pht('Disable or restore the import.'))->setConduitTypeDescription(pht('True to reload the import.'))->setValue(false)); if ($can_trigger) { $frequency_map = PhabricatorCalendarImport::getTriggerFrequencyMap(); $frequency_options = ipull($frequency_map, 'name'); $fields[] = id(new PhabricatorSelectEditField())->setKey('frequency')->setLabel(pht('Update Automatically'))->setDescription(pht('Configure an automatic update frequncy.'))->setTransactionType(PhabricatorCalendarImportFrequencyTransaction::TRANSACTIONTYPE)->setConduitDescription(pht('Set the automatic update frequency.'))->setConduitTypeDescription(pht('Update frequency constant.'))->setValue($object->getTriggerFrequency())->setOptions($frequency_options); } $import_engine = $object->getEngine(); foreach ($import_engine->newEditEngineFields($this, $object) as $field) { $fields[] = $field; } return $fields; }
protected final function queueDataImport(PhabricatorCalendarImport $import, $data) { $import->newLogMessage(PhabricatorCalendarImportQueueLogType::LOGTYPE, array('data.size' => strlen($data), 'data.limit' => self::QUEUE_BYTE_LIMIT)); // When we queue on this pathway, we're queueing in response to an explicit // user action (like uploading a big `.ics` file), so we queue at normal // priority instead of bulk/import priority. PhabricatorWorker::scheduleTask('PhabricatorCalendarImportReloadWorker', array('importPHID' => $import->getPHID(), 'via' => PhabricatorCalendarImportReloadWorker::VIA_BACKGROUND), array('objectPHID' => $import->getPHID())); }
private function buildImportedEvents(PhabricatorCalendarImport $import) { $viewer = $this->getViewer(); $engine = id(new PhabricatorCalendarEventSearchEngine())->setViewer($viewer); $saved = $engine->newSavedQuery()->setParameter('importSourcePHIDs', array($import->getPHID())); $pager = $engine->newPagerForSavedQuery($saved); $pager->setPageSize(25); $query = $engine->buildQueryFromSavedQuery($saved); $results = $engine->executeQuery($query, $pager); $view = $engine->renderResults($results, $saved); $list = $view->getObjectList(); $list->setNoDataString(pht('No imported events.')); $all_uri = $this->getApplicationURI(); $all_uri = (string) id(new PhutilURI($all_uri))->setQueryParam('importSourcePHID', $import->getPHID())->setQueryParam('display', 'list'); $all_button = id(new PHUIButtonView())->setTag('a')->setText(pht('View All'))->setIcon('fa-search')->setHref($all_uri); $header = id(new PHUIHeaderView())->setHeader(pht('Imported Events'))->addActionLink($all_button); return id(new PHUIObjectBoxView())->setHeader($header)->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->setObjectList($list); }