/** * Test whether splitting an recurring event saves the new event under a new UID. * See http://jira.opensource.mayflower.de/jira/browse/PHPROJEKT-298 for the ratio behind this. */ public function testSplittingRecurrenceGivesNewUidAndUri() { $this->setRequestUrl('Calendar2/index/jsonSave/nodeId/1/id/0'); $this->request->setParam('comments', ''); $this->request->setParam('confirmationStatus', '2'); $this->request->setParam('description', ''); $this->request->setParam('end', '2011-12-01 09:00'); $this->request->setParam('location', ''); $this->request->setParam('ownerId', '2'); $this->request->setParam('participants', '2'); $this->request->setParam('rrule', 'FREQ=DAILY;INTERVAL=1;BYDAY='); $this->request->setParam('sendNotification', '0'); $this->request->setParam('start', '2011-12-01 08:00'); $this->request->setParam('summary', 'test'); $this->request->setParam('visibility', '1'); $response = $this->getResponse(); $this->assertContains(IndexController::ADD_TRUE_TEXT, $response); $response = Zend_Json::decode(substr($response, 5, -1)); $this->assertArrayHasKey('id', $response); $firstId = $response['id']; $this->_reset(); $tzOffset = (int) Phprojekt_Auth_Proxy::getEffectiveUser()->getSetting('timeZone', '0'); $hour = 8 - $tzOffset; $hour = sprintf('%02d', $hour); $this->setRequestUrl("Calendar2/index/jsonSave/nodeId/1/id/{$firstId}/occurrence/2011-12-03%20{$hour}:00:00"); $this->request->setParam('comments', ''); $this->request->setParam('confirmationStatus', '2'); $this->request->setParam('description', ''); $this->request->setParam('end', '2011-12-03 09:00:00'); $this->request->setParam('location', ''); $this->request->setParam('multipleEvents', 'true'); $this->request->setParam('occurrence', '2011-12-03 08:00:00'); $this->request->setParam('ownerId', '2'); $this->request->setParam('participants', '2'); $this->request->setParam('rrule', 'FREQ=DAILY;INTERVAL=1;BYDAY='); $this->request->setParam('sendNotification', '0'); $this->request->setParam('start', '2011-12-03 08:00:00'); $this->request->setParam('summary', 'something else'); $this->request->setParam('visibility', '1'); $response = $this->getResponse(); $this->assertContains(IndexController::EDIT_TRUE_TEXT, $response); $response = Zend_Json::decode(substr($response, 5, -1)); $this->assertArrayHasKey('id', $response); $secondId = $response['id']; $first = new Calendar2_Models_Calendar2(); $first->find($firstId); $second = new Calendar2_Models_Calendar2(); $second->find($secondId); $this->assertNotEquals($first->uid, $second->uid); $this->assertNotEquals($first->uri, $second->uri); }
/** * Convert a UTC time to user or user to UTC and return the timestamp. * * @param string $value Date value to convert. * @param integer $side 1 for utc to user, -1 for user to utc. * * @return integer Unix timestamp value. */ public static function convert($value, $side) { $timeZone = Phprojekt_Auth_Proxy::getEffectiveUser()->getSetting("timeZone", 'UTC'); if (strstr($timeZone, "_")) { list($hours, $minutes) = explode("_", $timeZone); } else { $hours = (int) $timeZone; $minutes = 0; } $hoursComplement = $hours * $side; $minutesComplement = $minutes * $side; $u = strtotime($value); return mktime(date("H", $u) + $hoursComplement, date("i", $u) + $minutesComplement, date("s", $u), date("m", $u), date("d", $u), date("Y", $u)); }
/** * Returns the rights merged with the role for the current user. * * @return array Array of rights per user. */ public function getRights($userId = null) { // backward compatbility if (null === $userId) { $userId = Phprojekt_Auth_Proxy::getEffectiveUserId(); } $moduleId = Phprojekt_Module::getId($this->getModelName()); return Phprojekt_Right::getRightsForItems($moduleId, $this->projectId, $userId, array($this->id)); }
/** * Checks that the user has permission for modifying the item, in this case for uploading or deleting files. * * @param Phprojekt_Model_Interface $model Current module. * @param integer $itemId Current item id. * * @throws Exception On no write access. * * @return void */ private static function _checkWritePermission($model, $itemId) { if ($itemId != 0) { $model->find($itemId); } if (!$model->hasRight(Phprojekt_Auth_Proxy::getEffectiveUserId(), Phprojekt_Acl::WRITE)) { $error = Phprojekt::getInstance()->translate('You don\'t have permission for modifying this item.'); self::_logError("Error: trying to Delete or Upload a file without write access.", array(get_class($model), $itemId)); throw new Exception($error); } }
/** * Returns a list of all the users the current user has proxy rights on * * Returns a list of all the users with: * <pre> * - id => id of user. * - display => Display for the user. * - current => True or false if is the current user. * </pre> * * The return is in JSON format. * * @return void */ public function jsonGetProxyableUsersAction() { $current = Phprojekt_Auth_Proxy::getEffectiveUserId(); $proxyTable = new Phprojekt_Auth_ProxyTable(); $proxyUserIds = $proxyTable->getProxyableUsersForUserId(); $data = array(); foreach ($proxyUserIds as $user) { $data['data'][] = array('id' => (int) $user->id, 'display' => $user->displayName, 'current' => $current == $user->id); } Phprojekt_Converter_Json::echoConvert($data, Phprojekt_ModelInformation_Default::ORDERING_LIST); }
/** * Get a participant's confirmation status. * * If no id is given, the currently logged in user's status * will be returned. * * @param int $id The id of the participant. * * @return int */ public function getConfirmationStatus($id = null) { if (is_null($id)) { $id = Phprojekt_Auth_Proxy::getEffectiveUserId(); } $this->_fetchParticipantData(); if (!$this->hasParticipant($id)) { // We can not throw an exception here because if a user edits a new // entry, a empty model object will be requested and serialized. // Returning null here will yield the default value as configured // in the database_manager table. return null; } return $this->_participantData[$id]; }
/** * As defined in Sabre_CalDAV_Backend_Abstract * * Alters a calendar object. This is currently not supported if the event is recurring and any occurrences have been * modified in PHProjekt or if this operation would modify any speficic occurrences. * * @param string $calendarId The id of the calendar. Equals to the id of the user it belongs to. * @param string $objectUri The uri of the object. * @param string $calendarData The vobject data that the object should be modified to. * * @return void */ public function updateCalendarObject($calendarId, $objectUri, $calendarData) { $vcalendar = Sabre_VObject_Reader::read($calendarData); $timecard = new Timecard_Models_Timecard(); $timecard = $timecard->findByUri($objectUri); if (!$timecard) { throw new Sabre_DAV_Exception_NotFound("Timecard entry with uri {$objectUri} not found"); } if ($timecard->ownerId != Phprojekt_Auth_Proxy::getEffectiveUserId()) { throw new Sabre_DAV_Exception_Forbidden("You are not allowed to modify this entry"); } $timecard = Timecard_Models_VObjectReader::readBasedOnExistingTimecard($timecard, $vcalendar->vevent); $timecard->save(); }
/** * Check if the user has delete access to the item if is not a global module. * * @param Phprojekt_ActiveRecord_Abstract $model The model to save. * @param string $moduleName The current module. * * @return boolean True for a valid right. */ private static function _checkItemRights(Phprojekt_ActiveRecord_Abstract $model, $moduleName) { $canDelete = false; if ($moduleName == 'Core') { return Phprojekt_Auth::isAdminUser(); } else { if (Phprojekt_Module::saveTypeIsNormal(Phprojekt_Module::getId($moduleName)) && method_exists($model, 'hasRight')) { return $model->hasRight(Phprojekt_Auth_Proxy::getEffectiveUserId(), Phprojekt_Acl::DELETE); } else { return true; } } }
/** * Help to save a model by setting the models properties. * Validation is based on the ModelInformation implementation. * * @param Phprojekt_Model_Interface $model The model * @param array $params The parameters used to feed the model. * * @throws Exception If validation of parameters fails. * * @return boolean True for a sucessful save. */ protected static function _saveModel(Phprojekt_Model_Interface $model, array $params) { $newItem = empty($params['id']); $model = self::parameterToModel($model, $params, $newItem); $projectId = $model->hasField('projectId') ? $model->projectId : 0; $userId = Phprojekt_Auth_Proxy::getEffectiveUserId(); $moduleName = Phprojekt_Loader::getModuleFromObject($model); $moduleId = Phprojekt_Module::getId($moduleName); if (!$model->recordValidate()) { $errors = $model->getError(); $error = array_pop($errors); throw new Zend_Controller_Action_Exception($error['label'] . ': ' . $error['message'], 400); } if (!self::_checkModule($moduleId, $projectId)) { throw new Zend_Controller_Action_Exception('The parent project do not have enabled this module', 400); } $rights = Default_Helpers_Right::getRights($params); if ($model instanceof Phprojekt_Item_Abstract) { if ($newItem && !Phprojekt_Module::saveTypeIsGlobal($moduleId)) { $project = new Project_Models_Project(); $project->find($projectId); if (!$project->hasRight($userId, Phprojekt_Acl::CREATE)) { throw new Zend_Controller_Action_Exception('You do not have the necessary create right', 403); } $rights[$userId] = Phprojekt_Acl::ALL; } else { if (!$model->hasRight($userId, Phprojekt_Acl::WRITE)) { throw new Zend_Controller_Action_Exception('You do not have the necessary write right', 403); } } // Set the projectId to 1 for global modules // @TODO Remove the Timecard limitation if ($model->hasField('projectId') && Phprojekt_Module::saveTypeIsGlobal($moduleId) && Phprojekt_Module::getModuleName($moduleId) != 'Timecard') { $model->projectId = 1; } $model->save(); // Save access only if the user have "admin" right if ($newItem || $model->hasRight(Phprojekt_Auth_Proxy::getEffectiveUserId(), Phprojekt_Acl::ADMIN)) { if (!Phprojekt_Auth_Proxy::isAdminUser() && count($rights) <= 0) { throw new Zend_Controller_Action_Exception('At least one person must have access to this item', 400); } $model->saveRights($rights); } } else { $model->save(); $model->saveRights($rights); } return $model; }
/** * This function wraps around the phprojekt setting for the user timezone * to return a DateTimeZone object. * * @return DateTimeZone The timezone of the user. */ public static function getUserDateTimeZone() { $tz = Phprojekt_Auth_Proxy::getEffectiveUser()->getSetting('timezone', '0'); $tz = explode('_', $tz); $hours = (int) $tz[0]; if ($hours >= 0) { $hours = '+' . $hours; } $minutes = '00'; if (array_key_exists(1, $tz)) { // We don't need the minus sign $minutes = abs($tz[1]); } $datetime = new Datetime($hours . ':' . $minutes); return $datetime->getTimezone(); }
/** * Renders the upload.phtml template for display an upload field. * * This function draws the upload field in the form. * All the uploaded files are displayed with a cross for delete it and a link for download it. * * @param integer $itemId Current item id. * @param string $field Name of the field in the module. * @param string $value Value of the field. * * @return void */ private function _fileRenderView($itemId, $field, $files) { $this->getResponse()->clearHeaders(); $this->getResponse()->clearBody(); $sessionName = 'Phprojekt_CsrfToken'; $csrfNamespace = new Zend_Session_Namespace($sessionName); $config = Phprojekt::getInstance()->getConfig(); $linkBegin = 'index.php/' . $this->getModuleName() . '/index/'; $fieldId = $this->getRequest()->getParam('fieldId', ''); // Add all the extra parameters that have the original URL $linkData = ''; $removeParams = array('module', 'controller', 'field', 'id', 'csrfToken', 'action', 'MAX_FILE_SIZE', 'order'); foreach ($this->getRequest()->getParams() as $paramName => $paramValue) { if (!in_array($paramName, $removeParams)) { $linkData .= $paramName . '/' . $paramValue . '/'; } } $this->view->compressedDojo = (bool) $config->compressedDojo; $this->view->formPath = $linkBegin . 'fileUpload/' . $linkData; $this->view->downloadLink = ''; $this->view->fileName = null; $this->view->itemId = $itemId; $this->view->field = $field; $this->view->fieldId = $fieldId; $this->view->csrfToken = $csrfNamespace->token; $this->view->maxUploadSize = isset($config->maxUploadSize) ? (int) $config->maxUploadSize : Phprojekt::DEFAULT_MAX_UPLOAD_SIZE; $model = $this->getModelObject(); $model->find($itemId); $filesForView = array(); $hasDownloadRight = $model->hasRight(Phprojekt_Auth_Proxy::getEffectiveUserId(), Phprojekt_Acl::DOWNLOAD); $hasWriteRight = $model->hasRight(Phprojekt_Auth_Proxy::getEffectiveUserId(), Phprojekt_Acl::WRITE); $this->view->disabled = !$hasWriteRight; // Is there any file? if (!empty($files)) { $i = 0; foreach ($files as $file) { $fileName = $file['name']; $fileHash = $file['md5']; $fileData = 'id/' . $itemId . '/field/' . $field . '/hash/' . $fileHash . '/csrfToken/' . $csrfNamespace->token; $filesForView[$i] = array('fileName' => $fileName, 'hash' => $fileHash); if ($hasDownloadRight) { $filesForView[$i]['downloadLink'] = $linkBegin . 'fileDownload/' . $linkData . $fileData; } $fileinfo = Default_Helpers_Upload::getInfosFromFile($file); $filesForView[$i]['size'] = $fileinfo['size']; $filesForView[$i]['ctime'] = $fileinfo['ctime']; $i++; } } if (isset($this->view->errorMessage) && !empty($this->view->errorMessage)) { $filesForView[] = array(); } $this->view->files = $filesForView; $this->render('upload'); }
/** * Delete only the own records * * @return boolean */ public function delete() { if ($this->ownerId == Phprojekt_Auth_Proxy::getEffectiveUserId()) { return parent::delete(); } else { return false; } }
/** * Convert a model or a model information into a json stream. * * @param Phprojekt_Interface_Model | array $models The model(s) to convert. * @param integer $order A Phprojekt_ModelInformation_Default::ORDERING_* const that * defines the ordering for the convert. * * @return string Data in JSON format. */ private static function _convertModel($models, $order = Phprojekt_ModelInformation_Default::ORDERING_DEFAULT) { if (empty($models)) { throw new Exception('Called with empty value'); } // TODO: Are we sure every model is of the same type and have the same // parent? if (!is_array($models)) { $models = array($models); } $information = $models[0]->getInformation($order); $fieldDefinition = $information->getFieldDefinition($order); $datas = array(); $itemIds = array(); foreach ($models as $model) { if (!$model instanceof Phprojekt_Model_Interface) { throw new Exception("A given model does not implement the\n model interface."); } $data = array(); $data['id'] = (int) $model->id; $itemIds[] = $data['id']; foreach ($fieldDefinition as $field) { $key = $field['key']; $value = $model->{$key}; $data[$key] = self::_convertModelValue($value, $field); } $data['rights'] = array(); $datas[] = $data; } $userId = (int) Phprojekt_Auth_Proxy::getEffectiveUserId(); $moduleId = Phprojekt_Module::getId($models[0]->getModelName()); // Okay we got real models and stuff that pretends to be a model // so we try to guess if we the model has rights that we can access if ($models[0] instanceof Phprojekt_Item_Abstract) { if ($models[0] instanceof Project_Models_Project) { $projectId = $models[0]->id; } else { $projectId = $models[0]->projectId; } // TODO: we still asume that the getModelName call works $rights = Phprojekt_Right::getRightsForItems($moduleId, $projectId, $userId, $itemIds); // We need the $idx to modify the $datas elements instead of just copies. foreach ($datas as $index => $data) { $datas[$index]['rights'][$userId] = Phprojekt_Acl::convertBitmaskToArray($rights[$datas[$index]['id']]); } } $data = array('metadata' => $fieldDefinition, 'data' => $datas, 'numRows' => (int) count($datas)); return self::_makeJsonString($data); }
/** * Updates the current user's confirmation status on the given event. * * @param Calendar2_Models_Calendar2 $model The model to update. * @param Array $params The Request's parameters. All * values taken from this array * will be validated. * * @return int The id of the (new) model object. * * @throws Zend_Controller_Action_Exception On malformed $params content. */ private function _updateConfirmationStatusAction($model, $params) { $status = $params['confirmationStatus']; $multiple = array_key_exists('multipleEvents', $params) ? $params['multipleEvents'] : 'true'; if (!Cleaner::validate('int', $status) || !Calendar2_Models_Calendar2::isValidStatus((int) $status)) { throw new Zend_Controller_Action_Exception("Invalid confirmationStatus '{$status}'", 400); } if (!Cleaner::validate('boolean', $multiple)) { throw new Zend_Controller_Action_Exception("Invalid multiple '{$multiple}'", 400); } $status = (int) $status; $multiple = 'true' == strtolower($multiple); $model->setConfirmationStatus(Phprojekt_Auth_Proxy::getEffectiveUserId(), $status); if ($multiple) { $model->save(); } else { $model->saveSingleEvent(); } return $model->id; }
protected static function _getProxyTable() { if (is_null(self::$_proxyTable)) { self::$_proxyTable = new Phprojekt_Auth_ProxyTable(); } return self::$_proxyTable; }
/** * Return the value of one setting. * * @param string $settingName The name of the setting. * @param integer $userId The user ID, if is not setted, the current user is used. * * @return mix Value of the setting. */ public function getSetting($settingName, $userId = 0) { $toReturn = null; if (!$userId) { $userId = Phprojekt_Auth_Proxy::getEffectiveUserId(); } $namespace = new Zend_Session_Namespace(self::IDENTIFIER . $userId); if (!isset($namespace->{$settingName})) { $where = sprintf('user_id = %d AND key_value = %s AND module_id = %d', (int) $userId, $this->_db->quote($settingName), (int) $this->_moduleId); $record = $this->fetchAll($where); if (!empty($record)) { $toReturn = $record[0]->value; } $namespace->{$settingName} = $toReturn; } else { $toReturn = $namespace->{$settingName}; } return $toReturn; }