/** * Ensure everything works as expected. */ public function testApply_legacy() { $applyTests = $this->getApplyTests(); foreach ($applyTests as $test) { $source = $test['source']; $apply = $test['apply']; $result = $test['result']; \Conjoon_Util_Array::apply($source, $apply); foreach ($result as $key => $value) { $this->assertArrayHasKey($key, $source); $this->assertSame($value, $source[$key]); } } }
/** * Returns the meta data for the lob. * The following properties must exist in $data: * - path The complete path to the lob * - includeResource optional, if the lob should be returned as a string, * too * * @param array $data * * @return array An array with the following properties: * - dirname * - basename * - extension * - filename * - resource with the plain content of the lob, if * includeResource was set to true * or null if the path was not valid * * @throws Conjoon_Data_Exception */ public function getLobData(array $data) { Conjoon_Argument_Check::check(array('path' => array('type' => 'string')), $data); $path = $this->_sanitizePath($data['path']); if (!@file_exists($path)) { throw new Conjoon_Data_Exception("File \"{$path}\" does not seem to exist."); } if (@is_dir($path)) { throw new Conjoon_Data_Exception("Path \"{$path}\" seems to point to a directory."); } $lobData = array(); Conjoon_Util_Array::apply($lobData, pathinfo($path)); if (isset($data['includeResource']) && $data['includeResource']) { $fc = @file_get_contents($path); $lobData['resource'] = $fc !== false ? $fc : ""; $fc = null; } return $lobData; }
/** * A draft can be loaded from the database if an id was supplied * or filled with dummy data if no id was supplied. If no id was supplied, * the user wants to create a new email. In this case, the id defaults to * -1. If the user requests to save the draft later on, the id will be updated * to the value of the auto_increment field of the table. * Along with an id the application will need a folder_id so it can tell whether * an existing view has to be updated if this draft was edited and the folder * is currently visible. * Note, that getDraft will also be executed when the user wants to reply to * an email or forward an email. in this case, the id defaults to the email to * which the user wants to forward/ reply to. * * The method awaits 4 POST parameters: * id - the original message to reply to OR the id of the draft that is being * edited * type - the context the draft is in: can be either "new", "forward", * "reply", "reply_all" or "edit" * name: the name of an recipient to send this email to * address: the address of an recipient to send this email to. If that value is not * empty. id will be set to -1 and type will be set to new. If address equals * to name or if name is left empty, only the address will be used to send the * email to. Address is given presedence in any case */ public function getDraftAction() { if ($this->_helper->conjoonContext()->getCurrentContext() != self::CONTEXT_JSON) { /** * see Conjoon_Controller_Action_InvalidContextException */ require_once 'Conjoon/Controller/Action/InvalidContextException.php'; throw new Conjoon_Controller_Action_InvalidContextException("Invalid context for action, expected \"" . self::CONTEXT_JSON . "\", got \"" . $this->_helper->conjoonContext()->getCurrentContext() . "\""); } $path = $_POST['path']; // check if folder is remote folder /** * @see Conjoon_Text_Parser_Mail_MailboxFolderPathJsonParser */ require_once 'Conjoon/Text/Parser/Mail/MailboxFolderPathJsonParser.php'; $parser = new Conjoon_Text_Parser_Mail_MailboxFolderPathJsonParser(); $pathInfo = $parser->parse($path); /** * @see Conjoon_Modules_Groupware_Email_Folder_Facade */ require_once 'Conjoon/Modules/Groupware/Email/Folder/Facade.php'; $facade = Conjoon_Modules_Groupware_Email_Folder_Facade::getInstance(); if (!empty($pathInfo) && $facade->isRemoteFolder($pathInfo['rootId'])) { return $this->getDraftFromRemoteServer($_POST['id'], $path, $_POST['type']); } /** * @see Conjoon_Keys */ require_once 'Conjoon/Keys.php'; /** * @see Conjoon_BeanContext_Inspector */ require_once 'Conjoon/BeanContext/Inspector.php'; /** * @see Conjoon_Modules_Groupware_Email_Draft_Filter_DraftResponse */ require_once 'Conjoon/Modules/Groupware/Email/Draft/Filter/DraftResponse.php'; /** * @see Conjoon_Modules_Groupware_Email_Account_Model_Account */ require_once 'Conjoon/Modules/Groupware/Email/Account/Model/Account.php'; /** * @see Conjoon_Util_Array */ require_once 'Conjoon/Util/Array.php'; $auth = Zend_Registry::get(Conjoon_Keys::REGISTRY_AUTH_OBJECT); $userId = $auth->getIdentity()->getId(); $id = (int) $_POST['id']; $type = (string) $_POST['type']; $accountModel = new Conjoon_Modules_Groupware_Email_Account_Model_Account(); // create a new draft so that the user is able to write an email from scratch! if ($id <= 0) { /** * @see Conjoon_Modules_Groupware_Email_Draft */ require_once 'Conjoon/Modules/Groupware/Email/Draft.php'; $standardId = $accountModel->getStandardAccountIdForUser($userId); if ($standardId == 0) { $this->view->error = $this->getErrorDto('Error while opening draft', 'Please configure an email account first.', Conjoon_Error::LEVEL_ERROR); $this->view->draft = null; $this->view->success = false; return; } $post = $_POST; Conjoon_Util_Array::apply($post, array('groupwareEmailAccountsId' => $standardId, 'groupwareEmailFoldersId' => -1)); $draftFilter = new Conjoon_Modules_Groupware_Email_Draft_Filter_DraftResponse($post, Conjoon_Modules_Groupware_Email_Draft_Filter_DraftResponse::CONTEXT_NEW); $data = $draftFilter->getProcessedData(); $draft = Conjoon_BeanContext_Inspector::create('Conjoon_Modules_Groupware_Email_Draft', $data); $this->view->success = true; $this->view->error = null; $this->view->draft = $draft->getDto(); $this->view->type = $type; return; } // load an email to edit, to reply or to forward it /** * @see Conjoon_Modules_Groupware_Email_Draft_Model_Draft */ require_once 'Conjoon/Modules/Groupware/Email/Draft/Model/Draft.php'; $draftModel = new Conjoon_Modules_Groupware_Email_Draft_Model_Draft(); $draftData = $draftModel->getDraft($id, $userId, $type); if (empty($draftData)) { $this->view->error = $this->getErrorDto('Error while opening draft', 'Could not find the referenced draft.', Conjoon_Error::LEVEL_ERROR); $this->view->draft = null; $this->view->success = false; return; } switch ($type) { case 'reply': $context = Conjoon_Modules_Groupware_Email_Draft_Filter_DraftResponse::CONTEXT_REPLY; break; case 'reply_all': $context = Conjoon_Modules_Groupware_Email_Draft_Filter_DraftResponse::CONTEXT_REPLY_ALL; break; case 'forward': $context = Conjoon_Modules_Groupware_Email_Draft_Filter_DraftResponse::CONTEXT_FORWARD; break; case 'edit': $context = Conjoon_Modules_Groupware_Email_Draft_Filter_DraftResponse::CONTEXT_EDIT; break; default: throw new Exception("Type {$type} not supported."); break; } Conjoon_Util_Array::camelizeKeys($draftData); $addresses = $accountModel->getEmailAddressesForUser($userId); $draftData['userEmailAddresses'] = $addresses; /** * @ticket CN-708 * if context is not edit and equals to reply* or forward, read out the * "to" address and find the matching account we'll be using for setting as * account from which the mail gets edited */ $matchingAccountId = -1; if ($context !== Conjoon_Modules_Groupware_Email_Draft_Filter_DraftResponse::CONTEXT_EDIT) { $orgTo = $draftData['to']; $matchingAccountId = $this->guessMailAccountForAddress($orgTo); if ($matchingAccountId > -1) { $draftData['groupwareEmailAccountsId'] = $matchingAccountId; } } $draftFilter = new Conjoon_Modules_Groupware_Email_Draft_Filter_DraftResponse($draftData, $context); $data = $draftFilter->getProcessedData(); $templateData = $data; // needed for draft forward because of Bean_Inspector unset($data['userEmailAddresses']); unset($data['from']); unset($data['replyTo']); if ($type == 'forward') { $data['to'] = array(); $data['cc'] = array(); } // convert email addresses /** * @see Conjoon_Modules_Groupware_Email_Address */ require_once 'Conjoon/Modules/Groupware/Email/Address.php'; $to = array(); $cc = array(); $bcc = array(); foreach ($data['to'] as $add) { $to[] = new Conjoon_Modules_Groupware_Email_Address($add); } foreach ($data['cc'] as $add) { $cc[] = new Conjoon_Modules_Groupware_Email_Address($add); } foreach ($data['bcc'] as $add) { $bcc[] = new Conjoon_Modules_Groupware_Email_Address($add); } $data['to'] = $to; $data['cc'] = $cc; $data['bcc'] = $bcc; $draft = Conjoon_BeanContext_Inspector::create('Conjoon_Modules_Groupware_Email_Draft', $data)->getDto(); if ($type == 'forward') { $applicationPath = $this->_helper->registryAccess()->getApplicationPath(); /** * @see Conjoon_Text_PhpTemplate */ require_once 'Conjoon/Text/PhpTemplate.php'; /** * @see Conjoon_Filter_StringWrap */ require_once 'Conjoon/Filter/StringWrap.php'; /** * @see Zend_Filter_HtmlEntities */ require_once 'Zend/Filter/HtmlEntities.php'; $cfsw = new Conjoon_Filter_StringWrap('[Fwd: ', ']'); $zfhe = new Zend_Filter_HtmlEntities(array('quotestyle' => ENT_COMPAT, 'charset' => 'UTF-8')); $draft->subject = $cfsw->filter($templateData['subject']); $templateData['subject'] = $zfhe->filter($templateData['subject']); $phpTemplate = new Conjoon_Text_PhpTemplate(array(Conjoon_Text_PhpTemplate::PATH => $applicationPath . '/templates/groupware/email/message.forward.phtml', Conjoon_Text_PhpTemplate::VARS => $templateData)); $draft->contentTextPlain = $phpTemplate->getParsedTemplate(); } $this->view->success = true; $this->view->error = null; $this->view->draft = $draft; $this->view->type = $type; }
/** * Creates a lob. * Additional parameters will be added to the array during processing, * such as the generated key for the lob. * * @param array $data An associative array with at least the following * key/value pairs: * - resource The resource to fetch the content from. This can either be * a native resource or a string. If $isPath is set to true, the string * will be treatened as a path and the contents from the file found under * this path will be read out/copied/moved. * @param bool $isPath Whether to treat "resource" as a file path. * @param bool $move if §isPath is set to true, * * @param bool $move * * @return array|null an array with the submitted data, along with additional * properties applied during runtime, or null on failure. The $result will be * stored in the variable $dbResult * * @throws Conjoon_Data_Exception */ protected function _createLob(array &$data, $isPath = false, $move = false) { if (!isset($data['resource'])) { throw new Conjoon_Data_Exception("Property \"resource not available for \" _createLob."); } $resource = $data['resource']; $useFileSystem = $this->_isFileSystemUsedForLobs(); $lobStorageBasePath = $this->_getLobStorageBasePath(); $key = $this->_generateLobKey($data); $path = null; Conjoon_Util_Array::apply($data, array('key' => $key, 'lobStorageBasePath' => $lobStorageBasePath)); // try to create the folders first if filestorage is used, // so we still have the db as a fallback if ($lobStorageBasePath !== null && $useFileSystem === true) { $storageContainer = $this->_generateStorageContainerString($data); Conjoon_Util_Array::apply($data, array('storageContainer' => $storageContainer)); $path = $this->_createFolder($data); } // first off, create the needed data in the database // if path is null, the app is either configured not to use // the file system for storing lobs or soemthing went wrong // while trying to find the dir where to store the lob if ($path === null) { if (!is_resource($resource) && $isPath === true) { $result = $this->_addLobFromPathToDb($data); if ($move === true) { $this->_fileLobAccess->deleteLobForId($resource); } } else { if (is_resource($resource)) { $result = $this->_addLobFromResourceToDb($resource, $data); } else { // string $result = $this->_dbLobAccess->addLob($data); } } if ($result === null) { return null; } Conjoon_Util_Array::apply($data, array('dbResult' => $result)); return $data; } // create needed data for storing file in file system $resource = $data['resource']; $data['resource'] = ""; $id = (int) $this->_dbLobAccess->addLob($data); if ($id <= 0) { return null; } Conjoon_Util_Array::apply($data, array('id' => $id, 'resource' => $resource, 'dbResult' => $id)); $file = $this->_generateFileNameStringForLob($data); $fileName = $path . '/' . $file; // does the file already exist? if (@file_exists($fileName)) { $this->_dbLobAccess->deleteLobForId($id); return null; } // and finally, add the file contents to the file system if (is_resource($resource)) { $res = $this->_fileLobAccess->addLobFromStream(array('path' => $fileName, 'resource' => $resource)); } else { if ($isPath) { if ($move === true) { $res = $this->_fileLobAccess->moveLob(array('from' => $resource, 'to' => $path, 'name' => $file)); } else { $res = $this->_fileLobAccess->copyLob(array('from' => $resource, 'to' => $path, 'name' => $file)); } } else { $res = $this->_fileLobAccess->addLob(array('path' => $fileName, 'resource' => $resource)); } } if ($res === null) { $this->_dbLobAccess->deleteLobForId($id); return null; } return $data; }
/** * Saves a sent email into the database. * * @param Conjoon_Modules_Groupware_Email_Draft $message * @param Conjoon_Modules_Groupware_Email_Account $account * @param integer $userId * @param Conjoon_Mail_Sent $mailSent * @param string $type * @param integer $referencesId The id of the email that was refernced sending this * message. This argument will only be taken into account if $type euqals to * reply or reply_all * @param array $postedAttachments * @param array $removeAttachmentIds * * @return array the data from groupware_email_item associated with * the newly saved entry */ public function saveSentEmail(Conjoon_Modules_Groupware_Email_Draft $message, Conjoon_Modules_Groupware_Email_Account $account, $userId, Conjoon_Mail_Sent $mailSent, $type = "", $referencesId = -1, $postedAttachments = array(), $removeAttachmentIds = array()) { $mail = $mailSent->getMailObject(); $userId = (int) $userId; $accountId = (int) $account->getId(); $messageId = (int) $message->getId(); $referenceId = $referencesId <= 0 ? 0 : $referencesId; if ($userId <= 0 || $accountId <= 0) { return array(); } $referencesModel = new Conjoon_Modules_Groupware_Email_Item_Model_References(); $emailRecipientsFilter = new Conjoon_Filter_EmailRecipients(); $emailRecipientsToStringFilter = new Conjoon_Filter_EmailRecipientsToString(); $outboxModel = new Conjoon_Modules_Groupware_Email_Item_Model_Outbox(); $folderModel = new Conjoon_Modules_Groupware_Email_Folder_Model_Folder(); // first check the folder type of the email $folderId = $message->getGroupwareEmailFoldersId(); $messageType = 'scratch'; // negative/0, means the message was created from draft if ($folderId <= 0) { $messageType = 'scratch'; } else { // anything else needs the meta info type fetched out of the folder model $metaInfo = $folderModel->getMetaInfo($folderId); switch ($metaInfo) { case Conjoon_Modules_Groupware_Email_Folder_Model_Folder::META_INFO_OUTBOX: $messageType = 'outbox'; break; case Conjoon_Modules_Groupware_Email_Folder_Model_Folder::META_INFO_DRAFT: $messageType = 'draft'; break; // anything else is probably a reply or forward to an existing message in any other // folder // anything else is probably a reply or forward to an existing message in any other // folder default: $messageType = 'scratch'; break; } } // adjust the message type depending on the type if ($type == 'reply' || $type == 'reply_all' || $type == 'forward') { $messageType = 'scratch'; } // prefill update/insert arrays $sentFolderId = $folderModel->getSentFolder($accountId, $userId); $date = new Zend_Date($mail->getDate(), Zend_Date::RFC_2822); $replyTo = (string) $mail->getReplyTo(); $to = $message->getTo(); $cc = $message->getCc(); $bcc = $message->getBcc(); $fromAddress = new Conjoon_Modules_Groupware_Email_Address(array($account->getAddress(), $account->getUserName())); $toString = array(); foreach ($to as $recipient) { $toString[] = $recipient->__toString(); } $toString = implode(', ', $toString); $ccString = array(); foreach ($cc as $recipient) { $ccString[] = $recipient->__toString(); } $ccString = implode(', ', $ccString); $bccString = array(); foreach ($bcc as $recipient) { $bccString[] = $recipient->__toString(); } $bccString = implode(', ', $bccString); $outboxUpdate = array('sent_timestamp' => time(), 'raw_header' => $mailSent->getSentHeaderText(), 'raw_body' => $mailSent->getSentBodyText(), 'groupware_email_accounts_id' => $message->getGroupwareEmailAccountsId()); /** * @see Conjoon_Filter_DateToUtc */ require_once 'Conjoon/Filter/DateToUtc.php'; $filterToUtc = new Conjoon_Filter_DateToUtc(); $itemUpdate = array('reply_to' => $replyTo, 'from' => $fromAddress->__toString(), 'recipients' => $emailRecipientsToStringFilter->filter($emailRecipientsFilter->filter(array($toString, $ccString, $bccString))), 'sender' => $emailRecipientsToStringFilter->filter($emailRecipientsFilter->filter(array($fromAddress->__toString()))), 'groupware_email_folders_id' => $sentFolderId, 'date' => $filterToUtc->filter($date->get(Zend_Date::ISO_8601))); switch ($messageType) { // if the message was sent from an opened draft or from the outbox, // we simply can create a new entry in the tables, // as if it was created from scratch // if, however, the email was sent from drafts, a user might have updated // the addresses, the subject, the email text and the attachments. // those fields have to be updated in the datastorage as well case 'draft': Conjoon_Util_Array::apply($itemUpdate, array('subject' => $message->getSubject(), 'to' => $toString, 'cc' => $ccString, 'bcc' => $bccString, 'content_text_plain' => $message->getContentTextPlain(), 'content_text_html' => $message->getContentTextHtml())); $this->saveAttachmentsForDraft($message, $postedAttachments, $removeAttachmentIds); // most simple: mesageType is outbox which means we have simply to update a few fields // most simple: mesageType is outbox which means we have simply to update a few fields case 'outbox': if ($messageId <= 0 || $sentFolderId == 0) { return array(); } // the message might have referenced an item when it was created. // look up entry in reference table and set this to is_pending = false $referencesWhere = $referencesModel->getAdapter()->quoteInto('groupware_email_items_id = ?', $messageId) . ' AND ' . $referencesModel->getAdapter()->quoteInto('user_id = ?', $userId); $referencesModel->update(array('is_pending' => 0), $referencesWhere); $outboxWhere = $outboxModel->getAdapter()->quoteInto('groupware_email_items_id = ?', $messageId); $outboxModel->update($outboxUpdate, $outboxWhere); $itemWhere = $this->getAdapter()->quoteInto('id = ?', $messageId); $this->update($itemUpdate, $itemWhere); return $this->getItemForUser($messageId, $userId); break; // if the message was created from scratch, i.e. has no id and no folderId, // save a fresh row into the tables groupware_email_items_id, groupware_email_items_flags, // groupware_email_items_outbox // if the message was created from scratch, i.e. has no id and no folderId, // save a fresh row into the tables groupware_email_items_id, groupware_email_items_flags, // groupware_email_items_outbox case 'scratch': Conjoon_Util_Array::apply($itemUpdate, array('subject' => $message->getSubject(), 'to' => $toString, 'cc' => $ccString, 'bcc' => $bccString, 'in_reply_to' => $message->getInReplyTo(), 'references' => $message->getReferences(), 'content_text_plain' => $message->getContentTextPlain(), 'content_text_html' => $message->getContentTextHtml())); $messageId = (int) $this->insert($itemUpdate); if ($messageId <= 0) { return array(); } $flagModel = new Conjoon_Modules_Groupware_Email_Item_Model_Flag(); $referenceType = ''; if (($type == Conjoon_Modules_Groupware_Email_Keys::REFERENCE_TYPE_REPLY || $type == Conjoon_Modules_Groupware_Email_Keys::REFERENCE_TYPE_REPLY_ALL || $type == Conjoon_Modules_Groupware_Email_Keys::REFERENCE_TYPE_FORWARD) && $referenceId != 0) { $referenceType = $type; $referenceUpdate = array('groupware_email_items_id' => $messageId, 'user_id' => $userId, 'reference_items_id' => $referenceId, 'reference_type' => $referenceType); $referencesModel->insert($referenceUpdate); } $flagUpdate = array('groupware_email_items_id' => $messageId, 'user_id' => $userId, 'is_read' => 1, 'is_spam' => 0, 'is_deleted' => 0); $flagModel->insert($flagUpdate); Conjoon_Util_Array::apply($outboxUpdate, array('groupware_email_items_id' => $messageId)); $outboxModel->insert($outboxUpdate); $message->setId($messageId); $this->saveAttachmentsForDraft($message, $postedAttachments, $removeAttachmentIds); return $this->getItemForUser($messageId, $userId); break; } return null; }