getHash(); } catch (Exception $e) { throw new Exception("The specified segment is invalid: " . $e->getMessage()); } return $definition; } protected function checkSegmentName($name) { if (empty($name)) { throw new Exception("Invalid name for this custom segment."); } } protected function checkEnabledAllUsers($enabledAllUsers) { $enabledAllUsers = (int)$enabledAllUsers; if ($enabledAllUsers && !Piwik::hasUserSuperUserAccess() ) { throw new Exception("enabledAllUsers=1 requires Super User access"); } return $enabledAllUsers; } protected function checkIdSite($idSite) { if (empty($idSite)) { if (!Piwik::hasUserSuperUserAccess()) { throw new Exception($this->getMessageCannotEditSegmentCreatedBySuperUser()); } } else { if (!is_numeric($idSite)) { throw new Exception("idSite should be a numeric value"); } Piwik::checkUserHasViewAccess($idSite); } $idSite = (int)$idSite; return $idSite; } protected function checkAutoArchive($autoArchive, $idSite) { $autoArchive = (int)$autoArchive; if ($autoArchive) { $exception = new Exception("To prevent abuse, autoArchive=1 requires Super User or ControllerAdmin access."); if (empty($idSite)) { if (!Piwik::hasUserSuperUserAccess()) { throw $exception; } } else { if (!Piwik::isUserHasAdminAccess($idSite)) { throw $exception; } } } return $autoArchive; } protected function getSegmentOrFail($idSegment) { $segment = $this->get($idSegment); if (empty($segment)) { throw new Exception("Requested segment not found"); } return $segment; } protected function checkUserIsNotAnonymous() { if (Piwik::isUserIsAnonymous()) { throw new Exception("To create, edit or delete Custom Segments, please sign in first."); } } protected function checkUserCanModifySegment($segment) { if(Piwik::hasUserSuperUserAccess()) { return; } if($segment['login'] != Piwik::getCurrentUserLogin()) { throw new Exception($this->getMessageCannotEditSegmentCreatedBySuperUser()); } } /** * Deletes a stored segment. * * @param $idSegment * @return bool */ public function delete($idSegment) { $this->checkUserIsNotAnonymous(); $segment = $this->getSegmentOrFail($idSegment); $this->checkUserCanModifySegment($segment); $this->sendSegmentDeactivationEvent($idSegment); $db = Db::get(); $db->delete(Common::prefixTable('segment'), 'idsegment = ' . $idSegment); return true; } /** * Modifies an existing stored segment. * * @param int $idSegment The ID of the stored segment to modify. * @param string $name The new name of the segment. * @param string $definition The new definition of the segment. * @param bool $idSite If supplied, associates the stored segment with as single site. * @param bool $autoArchive Whether to automatically archive data with the segment or not. * @param bool $enabledAllUsers Whether the stored segment is viewable by all users or just the one that created it. * * @return bool */ public function update($idSegment, $name, $definition, $idSite = false, $autoArchive = false, $enabledAllUsers = false) { $this->checkUserIsNotAnonymous(); $segment = $this->getSegmentOrFail($idSegment); $this->checkUserCanModifySegment($segment); $idSite = $this->checkIdSite($idSite); $this->checkSegmentName($name); $definition = $this->checkSegmentValue($definition, $idSite); $enabledAllUsers = $this->checkEnabledAllUsers($enabledAllUsers); $autoArchive = $this->checkAutoArchive($autoArchive, $idSite); if ($this->segmentVisibilityIsReduced($idSite, $enabledAllUsers, $segment)) { $this->sendSegmentDeactivationEvent($idSegment); } $bind = array( 'name' => $name, 'definition' => $definition, 'enable_all_users' => $enabledAllUsers, 'enable_only_idsite' => $idSite, 'auto_archive' => $autoArchive, 'ts_last_edit' => Date::now()->getDatetime(), ); $db = Db::get(); $db->update(Common::prefixTable("segment"), $bind, "idsegment = $idSegment" ); return true; } /** * Adds a new stored segment. * * @param string $name The new name of the segment. * @param string $definition The new definition of the segment. * @param bool $idSite If supplied, associates the stored segment with as single site. * @param bool $autoArchive Whether to automatically archive data with the segment or not. * @param bool $enabledAllUsers Whether the stored segment is viewable by all users or just the one that created it. * * @return int The newly created segment Id */ public function add($name, $definition, $idSite = false, $autoArchive = false, $enabledAllUsers = false) { $this->checkUserIsNotAnonymous(); $idSite = $this->checkIdSite($idSite); $this->checkSegmentName($name); $definition = $this->checkSegmentValue($definition, $idSite); $enabledAllUsers = $this->checkEnabledAllUsers($enabledAllUsers); $autoArchive = $this->checkAutoArchive($autoArchive, $idSite); $db = Db::get(); $bind = array( 'name' => $name, 'definition' => $definition, 'login' => Piwik::getCurrentUserLogin(), 'enable_all_users' => $enabledAllUsers, 'enable_only_idsite' => $idSite, 'auto_archive' => $autoArchive, 'ts_created' => Date::now()->getDatetime(), 'deleted' => 0, ); $db->insert(Common::prefixTable("segment"), $bind); return $db->lastInsertId(); } /** * Returns a stored segment by ID * * @param $idSegment * @throws Exception * @return bool */ public function get($idSegment) { Piwik::checkUserHasSomeViewAccess(); if (!is_numeric($idSegment)) { throw new Exception("idSegment should be numeric."); } $segment = Db::get()->fetchRow("SELECT * " . " FROM " . Common::prefixTable("segment") . " WHERE idsegment = ?", $idSegment); if (empty($segment)) { return false; } try { if (!$segment['enable_all_users']) { Piwik::checkUserHasSuperUserAccessOrIsTheUser($segment['login']); } } catch (Exception $e) { throw new Exception($this->getMessageCannotEditSegmentCreatedBySuperUser()); } if ($segment['deleted']) { throw new Exception("This segment is marked as deleted. "); } return $segment; } /** * Returns all stored segments. * * @param bool|int $idSite Whether to return stored segments for a specific idSite, or all of them. If supplied, must be a valid site ID. * @return array */ public function getAll($idSite = false) { if (!empty($idSite)) { Piwik::checkUserHasViewAccess($idSite); } else { Piwik::checkUserHasSomeViewAccess(); } $userLogin = Piwik::getCurrentUserLogin(); $model = new Model(); if (empty($idSite)) { $segments = $model->getAllSegments($userLogin); } else { $segments = $model->getAllSegmentsForSite($idSite, $userLogin); } return $segments; } /** * When deleting or making a segment invisible, allow plugins to throw an exception or propagate the action * * @param $idSegment */ private function sendSegmentDeactivationEvent($idSegment) { /** * Triggered before a segment is deleted or made invisible. * * This event can be used by plugins to throw an exception * or do something else. * * @param int $idSegment The ID of the segment being deleted. */ Piwik::postEvent(self::DEACTIVATE_SEGMENT_EVENT, array($idSegment)); } /** * @param $idSiteNewValue * @param $enableAllUserNewValue * @param $segment * @return bool */ private function segmentVisibilityIsReduced($idSiteNewValue, $enableAllUserNewValue, $segment) { $allUserVisibilityIsDropped = $segment['enable_all_users'] && !$enableAllUserNewValue; $allWebsiteVisibilityIsDropped = !isset($segment['idSite']) && $idSiteNewValue; return $allUserVisibilityIsDropped || $allWebsiteVisibilityIsDropped; } /** * @return string */ private function getMessageCannotEditSegmentCreatedBySuperUser() { $message = "You can only edit and delete custom segments that you have created yourself. This segment was created and 'shared with you' by the Super User. " . "To modify this segment, you can first create a new one by clicking on 'Add new segment'. Then you can customize the segment's definition."; return $message; } }