/** * Finds cost centres by key * It searches by name or billing number * * @param string $key optional Search key * @return ArrayCollection Returns collection of the CostCentreEntity objects */ public function findByKey($key = null) { if (is_null($key) || $key === '') { return $this->all(); } $collection = new ArrayCollection(); $ccEntity = new CostCentreEntity(); $rs = $this->db->Execute("\n SELECT " . $ccEntity->fields('c') . "\n FROM " . $ccEntity->table('c') . "\n WHERE c.`name` LIKE ?\n OR EXISTS (\n SELECT 1 FROM cc_properties cp\n WHERE `cp`.cc_id = `c`.`cc_id`\n AND `cp`.`name` = ? AND `cp`.`value` LIKE ?\n )\n ", ['%' . $key . '%', CostCentrePropertyEntity::NAME_BILLING_CODE, '%' . $key . '%']); while ($rec = $rs->FetchRow()) { $item = new CostCentreEntity(); $item->load($rec); $collection->append($item); } return $collection; }
/** * Gets a list of environments by key * * @param string $query Search query * @return array Returns array of environments */ private function getEnvironmentsList($query = null) { $envs = []; $environments = $this->user->getEnvironments($query); if (count($environments) > 0) { $iterator = ChartPeriodIterator::create('month', gmdate('Y-m-01'), null, 'UTC'); //It calculates usage for all provided enviroments $usage = $this->getContainer()->analytics->usage->getFarmData($this->user->getAccountId(), [], $iterator->getStart(), $iterator->getEnd(), [TagEntity::TAG_ID_ENVIRONMENT, TagEntity::TAG_ID_FARM]); //It calculates usage for previous period same days $prevusage = $this->getContainer()->analytics->usage->getFarmData($this->user->getAccountId(), [], $iterator->getPreviousStart(), $iterator->getPreviousEnd(), [TagEntity::TAG_ID_ENVIRONMENT, TagEntity::TAG_ID_FARM]); foreach ($environments as $env) { if (isset($usage['data'][$env['id']]['data'])) { $envs[$env['id']]['topSpender'] = $this->getFarmTopSpender($usage['data'][$env['id']]['data']); } else { $envs[$env['id']]['topSpender'] = null; } $envs[$env['id']]['name'] = $env['name']; $envs[$env['id']]['envId'] = $env['id']; $ccId = \Scalr_Environment::init()->loadById($env['id'])->getPlatformConfigValue(\Scalr_Environment::SETTING_CC_ID); if (!empty($ccId)) { $envs[$env['id']]['ccId'] = $ccId; $envs[$env['id']]['ccName'] = CostCentreEntity::findPk($ccId)->name; } $totalCost = round(isset($usage['data'][$env['id']]) ? $usage['data'][$env['id']]['cost'] : 0, 2); $prevCost = round(isset($prevusage['data'][$env['id']]) ? $prevusage['data'][$env['id']]['cost'] : 0, 2); $envs[$env['id']] = $this->getWrappedUsageData(['iterator' => $iterator, 'usage' => $totalCost, 'prevusage' => $prevCost]) + $envs[$env['id']]; } } return array_values($envs); }
public function _billingCode($from, $to, $action) { switch ($action) { case static::ACT_CONVERT_TO_OBJECT: /* @var $from CostCentreEntity */ $to->billingCode = $from->getProperty(CostCentrePropertyEntity::NAME_BILLING_CODE); break; case static::ACT_CONVERT_TO_ENTITY: /** @var $to CostCentreEntity */ throw new NotYetImplementedException(); break; case static::ACT_GET_FILTER_CRITERIA: $cc = new CostCentreEntity(); $property = new CostCentrePropertyEntity(); return [AbstractEntity::STMT_FROM => $cc->table() . " LEFT JOIN " . $property->table() . " ON {$property->columnCcId} = {$cc->columnCcId}", AbstractEntity::STMT_WHERE => "{$property->columnName} = '" . CostCentrePropertyEntity::NAME_BILLING_CODE . "' AND {$property->columnValue} = " . $property->qstr('value', $from->billingCode)]; } }
public function defaultAction() { $ccs = array(); $projects = array(); foreach (CostCentreEntity::find([['archived' => 0]]) as $cc) { $ccs[$cc->ccId] = $cc->name; } foreach (ProjectEntity::find([['archived' => 0]]) as $project) { $projects[$project->projectId] = $project->name; } $this->response->page('ui/admin/analytics/notifications/view.js', array('notifications.ccs' => NotificationEntity::findBySubjectType(NotificationEntity::SUBJECT_TYPE_CC)->getArrayCopy(), 'notifications.projects' => NotificationEntity::findBySubjectType(NotificationEntity::SUBJECT_TYPE_PROJECT)->getArrayCopy(), 'reports' => ReportEntity::all()->getArrayCopy(), 'ccs' => $ccs, 'projects' => $projects), array(), array('ui/admin/analytics/notifications/view.css')); }
public function defaultAction() { $ccs = array(); $projects = array(); foreach (CostCentreEntity::find([['archived' => 0]]) as $cc) { $ccs[$cc->ccId] = $cc->name; } foreach (ProjectEntity::find([['archived' => 0]]) as $project) { $projects[$project->projectId] = $project->name; } $this->response->page('ui/analytics/notifications/view.js', array('notifications.ccs' => array('enabled' => SettingEntity::getValue(SettingEntity::ID_NOTIFICATIONS_CCS_ENABLED), 'items' => NotificationEntity::findBySubjectType(NotificationEntity::SUBJECT_TYPE_CC)), 'notifications.projects' => array('enabled' => SettingEntity::getValue(SettingEntity::ID_NOTIFICATIONS_PROJECTS_ENABLED), 'items' => NotificationEntity::findBySubjectType(NotificationEntity::SUBJECT_TYPE_PROJECT)), 'reports' => array('enabled' => SettingEntity::getValue(SettingEntity::ID_REPORTS_ENABLED), 'items' => ReportEntity::all()), 'ccs' => $ccs, 'projects' => $projects), array(), array()); }
/** * Gets specified Script taking into account both scope and authentication token * * @param string $ccId Unique identifier of the Cost-Center * * @return CostCentreEntity Returns the Project Entity on success * * @throws ApiErrorException * */ public function getCostCenter($ccId) { /* @var $cc CostCentreEntity */ $cc = CostCentreEntity::findPk($ccId); if (!$cc) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Requested Cost Center either does not exist or is not owned by your environment."); } if (!$this->hasPermissions($cc)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } return $cc; }
public function defaultAction() { $ccs = []; $projects = []; foreach (CostCentreEntity::find([['archived' => 0]]) as $cc) { /* @var $cc CostCentreEntity */ $ccs[$cc->ccId] = $cc->name; } foreach (ProjectEntity::find([['archived' => 0]]) as $project) { /* @var $project ProjectEntity */ $projects[$project->projectId] = $project->name; } $this->response->page('ui/admin/analytics/notifications/view.js', ['notifications.ccs' => NotificationEntity::findBySubjectType(NotificationEntity::SUBJECT_TYPE_CC)->getArrayCopy(), 'notifications.projects' => NotificationEntity::find([['subjectType' => NotificationEntity::SUBJECT_TYPE_PROJECT], ['accountId' => null]])->getArrayCopy(), 'reports' => ReportEntity::find([['accountId' => null]])->getArrayCopy(), 'ccs' => $ccs, 'projects' => $projects], [], ['ui/admin/analytics/notifications/view.css']); }
/** * @test */ public function textComplex() { $ccs = $this->listCostCenters(); $adapter = $this->getAdapter('costCenter'); foreach ($ccs as $cc) { foreach ($adapter->getRules()[ApiEntityAdapter::RULE_TYPE_FILTERABLE] as $property) { foreach ($this->listCostCenters([$property => $cc->{$property}]) as $filteredProject) { $this->assertEquals($cc->{$property}, $filteredProject->{$property}); } } $response = $this->getCostCenter($cc->id); $this->assertEquals(200, $response->status, $this->printResponseError($response)); $dbProject = CostCentreEntity::findPk($cc->id); $this->assertObjectEqualsEntity($response->getBody()->data, $dbProject, $adapter); } }
/** * Edit project action * * @param string $projectId * @throws Scalr_UI_Exception_NotFound */ public function editAction($projectId = null) { $scope = $this->request->getScope(); $this->request->restrictAccess(Acl::RESOURCE_ANALYTICS_ACCOUNT, Acl::PERM_ANALYTICS_ACCOUNT_MANAGE_PROJECTS); if (!empty($projectId)) { $project = $this->getContainer()->analytics->projects->get($projectId); if ($project->shared != ProjectEntity::SHARED_WITHIN_ACCOUNT || $project->accountId != $this->user->getAccountId()) { throw new Scalr_Exception_InsufficientPermissions(); } $cc = $project->getCostCenter(); $projectData = $this->getProjectData($project, true); //Check whether it can be removed try { $projectData['removable'] = $project->checkRemoval(); } catch (AnalyticsException $e) { $projectData['removable'] = false; $projectData['warning'] = $e->getMessage(); } } else { if ($scope == 'environment') { $cc = $this->getContainer()->analytics->ccs->get($this->getEnvironment()->getPlatformConfigValue(\Scalr_Environment::SETTING_CC_ID)); } $projectData = []; } $ccs = []; if ($scope == 'environment') { $accountCcs = AccountCostCenterEntity::findOne([['accountId' => $this->user->getAccountId()], ['ccId' => $cc->ccId]]); if ($accountCcs instanceof AccountCostCenterEntity) { $ccs[$cc->ccId] = ['ccId' => $cc->ccId, 'name' => $cc->name, 'billingCode' => $cc->getProperty(CostCentrePropertyEntity::NAME_BILLING_CODE)]; } } elseif ($scope == 'account') { foreach ($this->user->getEnvironments() as $row) { $env = \Scalr_Environment::init()->loadById($row['id']); $ccEntity = CostCentreEntity::findPk($env->getPlatformConfigValue(\Scalr_Environment::SETTING_CC_ID)); /* @var $ccEntity \Scalr\Stats\CostAnalytics\Entity\CostCentreEntity */ if ($ccEntity) { $accountCcs = AccountCostCenterEntity::findOne([['accountId' => $env->clientId], ['ccId' => $ccEntity->ccId]]); if ($accountCcs instanceof AccountCostCenterEntity) { $ccs[$ccEntity->ccId] = ['ccId' => $ccEntity->ccId, 'name' => $ccEntity->name, 'billingCode' => $ccEntity->getProperty(CostCentrePropertyEntity::NAME_BILLING_CODE)]; } } } } $this->response->page('ui/admin/analytics/projects/edit.js', array('project' => $projectData, 'ccs' => $ccs, 'scope' => 'account')); }
/** * Gets specified Script taking into account both scope and authentication token * * @param string $ccId Unique identifier of the Cost-Center * * @return CostCentreEntity Returns the Project Entity on success * * @throws ApiErrorException * */ public function getCostCenter($ccId) { //TODO: correct ACL resource $this->checkPermissions(Acl::RESOURCE_ANALYTICS_PROJECTS); if ($ccId != $this->getEnvironmentCostCenterId()) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Requested Cost Center either does not exist or is not owned by your environment."); } /* @var $cc CostCentreEntity */ $cc = CostCentreEntity::findPk($ccId); if (!$cc) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Requested Cost Center either does not exist or is not owned by your environment."); } if (!$this->hasPermissions($cc)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } return $cc; }
/** * Checks if user has access to project or cost center * * @param string $projectId optional Id of the project * @param string $ccId optional Id of the cost center * @return boolean Returns false if user is not lead of the subject */ public function isSubjectLead($projectId = null, $ccId = null) { if (!empty($projectId)) { $project = ProjectEntity::findPk($projectId); if (empty($project) || $project->getProperty(ProjectPropertyEntity::NAME_LEAD_EMAIL) !== $this->getEmail()) { return false; } } else { if (!empty($ccId)) { $ccs = CostCentreEntity::findPk($ccId); if (empty($ccs) || $ccs->getProperty(CostCentrePropertyEntity::NAME_LEAD_EMAIL) !== $this->getEmail()) { return false; } } } return true; }
/** * {@inheritdoc} * @see \Scalr\System\Pcntl\ProcessInterface::OnStartForking() */ public function OnStartForking() { if (!\Scalr::getContainer()->analytics->enabled) { die("Terminating the process as Cost analytics is disabled in the config.\n"); } $this->console->out("%s (UTC) Start Analytics Notifications process", gmdate('Y-m-d')); if (SettingEntity::getValue(SettingEntity::ID_NOTIFICATIONS_CCS_ENABLED) || SettingEntity::getValue(SettingEntity::ID_NOTIFICATIONS_PROJECTS_ENABLED)) { $this->console->out('Calculating data for projects notifications'); $quarters = new Quarters(SettingEntity::getQuarters()); $date = $quarters->getPeriodForDate('yesterday'); $formatedTitle = 'Q' . $quarters->getQuarterForDate('now') . ' budget (' . (new \DateTime('now', new \DateTimeZone('UTC')))->format('M j, Y') . ')'; $projects = ProjectEntity::find(); foreach ($projects as $project) { $periodProjectData = \Scalr::getContainer()->analytics->usage->getProjectPeriodData($project->projectId, 'quarter', $date->start->format('Y-m-d'), $date->end->format('Y-m-d')); $projectAnalytics[$project->projectId] = ['budget' => $periodProjectData['totals']['budget'], 'name' => $project->name, 'trends' => $periodProjectData['totals']['trends'], 'forecastCost' => $periodProjectData['totals']['forecastCost'], 'interval' => $periodProjectData['interval'], 'jsonVersion' => '1.0.0', 'farms' => []]; if (!empty($periodProjectData['totals']['farms'])) { foreach ($periodProjectData['totals']['farms'] as $farm) { $projectAnalytics[$project->projectId]['farms'][] = ['id' => $farm['id'], 'name' => $farm['name'], 'median' => $farm['median'] / 7, 'cost' => $farm['cost'], 'costPct' => $farm['costPct']]; } if (count($projectAnalytics[$project->projectId]['farms'] > 1)) { usort($projectAnalytics[$project->projectId]['farms'], array($this, 'sortItems')); if (count($projectAnalytics[$project->projectId]['farms'] > 6)) { array_splice($projectAnalytics[$project->projectId]['farms'], 6, count($projectAnalytics[$project->projectId]['farms'])); } } } $projectAnalytics[$project->projectId]['date'] = $formatedTitle; if ($project->archived) { continue; } if (SettingEntity::getValue(SettingEntity::ID_NOTIFICATIONS_PROJECTS_ENABLED)) { $projectNotifications = NotificationEntity::findBySubjectType(NotificationEntity::SUBJECT_TYPE_PROJECT); foreach ($projectNotifications as $notification) { $this->saveNotificationData('project', $notification, $project->projectId, $projectAnalytics); } } } } if (SettingEntity::getValue(SettingEntity::ID_NOTIFICATIONS_CCS_ENABLED)) { $this->console->out('Calculating data for cost center notifications'); $ccs = CostCentreEntity::find(); foreach ($ccs as $cc) { if ($cc->archived) { continue; } $periodCostCenterData = \Scalr::getContainer()->analytics->usage->getCostCenterPeriodData($cc->ccId, 'quarter', $date->start->format('Y-m-d'), $date->end->format('Y-m-d')); $ccAnalytics[$cc->ccId] = ['budget' => $periodCostCenterData['totals']['budget'], 'name' => $cc->name, 'trends' => $periodCostCenterData['totals']['trends'], 'forecastCost' => $periodCostCenterData['totals']['forecastCost'], 'interval' => $periodCostCenterData['interval'], 'jsonVersion' => '1.0.0', 'projects' => []]; if (!empty($periodCostCenterData['totals']['projects'])) { foreach ($periodCostCenterData['totals']['projects'] as $key => $project) { if (!empty($project['id'])) { $projectBudget = $projectAnalytics[$project['id']]['budget']; $projectBudget['name'] = $project['name']; $projectBudget['id'] = $project['id']; $projectBudget['median'] = $project['median'] / 7; $ccAnalytics[$cc->ccId]['projects'][] = $projectBudget; } else { $otherProjectsKey = $key; } } if (isset($otherProjectsKey)) { $ccAnalytics[$cc->ccId]['projects'][] = ['id' => '', 'budgetSpent' => $periodCostCenterData['totals']['projects'][$otherProjectsKey]['cost'], 'median' => $periodCostCenterData['totals']['projects'][$otherProjectsKey]['median'] / 7, 'name' => $periodCostCenterData['totals']['projects'][$otherProjectsKey]['name'], 'estimateOverspend' => null]; unset($otherProjectsKey); } if (count($ccAnalytics[$cc->ccId]['projects'] > 1)) { usort($ccAnalytics[$cc->ccId]['projects'], array($this, 'sortItems')); if (count($ccAnalytics[$cc->ccId]['projects'] > 6)) { array_splice($ccAnalytics[$cc->ccId]['projects'], 6, count($ccAnalytics[$cc->ccId]['projects'])); } } } $ccAnalytics[$cc->ccId]['date'] = $formatedTitle; $ccsNotifications = NotificationEntity::findBySubjectType(NotificationEntity::SUBJECT_TYPE_CC); foreach ($ccsNotifications as $notification) { $this->saveNotificationData('cc', $notification, $cc->ccId, $ccAnalytics); } } } if (SettingEntity::getValue(SettingEntity::ID_REPORTS_ENABLED)) { $this->console->out('Calculating data for reports'); $reports = ReportEntity::find(); foreach ($reports as $report) { switch ($report->period) { case ReportEntity::PERIOD_DAILY: $period = 'custom'; $start = (new \DateTime('yesterday', new \DateTimeZone('UTC')))->format('Y-m-d'); $end = $start; $startForecast = (new \DateTime('first day of this month', new \DateTimeZone('UTC')))->format('Y-m-d'); $endForecast = (new \DateTime('last day of this month', new \DateTimeZone('UTC')))->format('Y-m-d'); if ($startForecast == (new \DateTime('now', new \DateTimeZone('UTC')))->format('Y-m-d')) { $startForecast = (new \DateTime('first day of last month', new \DateTimeZone('UTC')))->format('Y-m-d'); $endForecast = (new \DateTime('last day of last month', new \DateTimeZone('UTC')))->format('Y-m-d'); } $periodForecast = 'month'; $formatedTitle = (new \DateTime($start, new \DateTimeZone('UTC')))->format('M j'); break; case ReportEntity::PERIOD_MONTHLY: $period = 'month'; $start = (new \DateTime('first day of last month', new \DateTimeZone('UTC')))->format('Y-m-d'); $end = (new \DateTime('last day of last month', new \DateTimeZone('UTC')))->format('Y-m-d'); $quarters = new Quarters(SettingEntity::getQuarters()); $currentQuarter = $quarters->getQuarterForDate(new \DateTime($start, new \DateTimeZone('UTC'))); $currentYear = (new \DateTime($start, new \DateTimeZone('UTC')))->format('Y'); $date = $quarters->getPeriodForQuarter($currentQuarter, $currentYear); $formatedTitle = (new \DateTime($start, new \DateTimeZone('UTC')))->format('M Y'); $startForecast = $date->start->format('Y-m-d'); $endForecast = $date->end->format('Y-m-d'); $periodForecast = 'quarter'; break; case ReportEntity::PERIOD_QUARTELY: $period = 'quarter'; $quarters = new Quarters(SettingEntity::getQuarters()); $currentQuarter = $quarters->getQuarterForDate(new \DateTime('yesterday', new \DateTimeZone('UTC'))); $currentYear = (new \DateTime('yesterday', new \DateTimeZone('UTC')))->format('Y'); if ($currentQuarter === 1) { $quarter = 4; $year = $currentYear - 1; } else { $quarter = $currentQuarter - 1; $year = $currentYear; } $date = $quarters->getPeriodForQuarter($quarter, $year); $start = $date->start->format('Y-m-d'); $end = $date->end->format('Y-m-d'); $formatedTitle = 'Q' . $quarter . ' ' . $year; $startForecast = $currentYear . '-01-01'; $endForecast = $currentYear . '-12-31'; $periodForecast = 'year'; break; case ReportEntity::PERIOD_WEEKLY: $period = 'week'; $end = (new \DateTime('yesterday', new \DateTimeZone('UTC')))->modify('last saturday')->format('Y-m-d'); $start = (new \DateTime($end, new \DateTimeZone('UTC')))->modify('last sunday')->format('Y-m-d'); $formatedTitle = (new \DateTime($start, new \DateTimeZone('UTC')))->format('M j') . ' - ' . (new \DateTime($end, new \DateTimeZone('UTC')))->format('M j'); $startForecast = (new \DateTime('first day of this month', new \DateTimeZone('UTC')))->format('Y-m-d'); $endForecast = (new \DateTime('last day of this month', new \DateTimeZone('UTC')))->format('Y-m-d'); if ($startForecast == (new \DateTime('now', new \DateTimeZone('UTC')))->format('Y-m-d')) { $startForecast = (new \DateTime('first day of last month', new \DateTimeZone('UTC')))->format('Y-m-d'); $endForecast = (new \DateTime('last day of last month', new \DateTimeZone('UTC')))->format('Y-m-d'); } $periodForecast = 'month'; break; } if ($report->subjectType === ReportEntity::SUBJECT_TYPE_CC) { $getPeriodicSubjectData = 'getCostCenterPeriodData'; $subjectEntityName = 'Scalr\\Stats\\CostAnalytics\\Entity\\CostCentre'; $subjectId = 'ccId'; } else { if ($report->subjectType === ReportEntity::SUBJECT_TYPE_PROJECT) { $getPeriodicSubjectData = 'getProjectPeriodData'; $subjectEntityName = 'Scalr\\Stats\\CostAnalytics\\Entity\\Project'; $subjectId = 'projectId'; } else { $periodData = \Scalr::getContainer()->analytics->usage->getDashboardPeriodData($period, $start, $end); $periodDataForecast = \Scalr::getContainer()->analytics->usage->getDashboardPeriodData($periodForecast, $startForecast, $endForecast); $periodData['period'] = $period; $periodData['forecastPeriod'] = $periodForecast; $periodData['totals']['forecastCost'] = $periodDataForecast['totals']['forecastCost']; $periodData['totals']['trends'] = $periodDataForecast['totals']['trends']; $periodData['name'] = 'Cloud Cost Report'; $periodData['jsonVersion'] = '1.0.0'; $periodData['totals']['clouds'] = $this->changeCloudNames($periodData['totals']['clouds']); $periodData['date'] = $formatedTitle; $periodData['totals']['budget']['budget'] = null; if ($period == 'quarter') { $periodData['totals']['budget'] = ['quarter' => $quarter, 'year' => $year, 'quarterStartDate' => $start, 'quarterEndDate' => $end]; } else { if ($period == 'month') { $periodData['totals']['budget'] = ['quarter' => $currentQuarter]; } } unset($periodData['projects'], $periodData['budget']['projects']); if (count($periodData['costcenters'] > 1)) { uasort($periodData['costcenters'], array($this, 'sortItems')); if (count($periodData['costcenters'] > 6)) { array_splice($periodData['costcenters'], 6, count($periodData['costcenters'])); } } if (count($periodData['totals']['clouds'] > 1)) { usort($periodData['totals']['clouds'], array($this, 'sortItems')); } $entity = ReportPayloadEntity::init([$report->subjectType, $report->subjectId, $period], $periodData, $start); if (!ReportPayloadEntity::findPk($entity->uuid)) { $payload = json_decode($entity->payload, true); \Scalr::getContainer()->mailer->setSubject('Summary report.')->setContentType('text/html')->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/report_summary.html.php', $payload, $report->emails); $this->console->out('Summary report email has been sent'); $payload['date'] = $entity->created->format('Y-m-d'); $entity->payload = json_encode($payload); $entity->save(); } } } unset($currentQuarter, $currentYear); if (!empty($report->subjectType) && !empty($report->subjectId)) { $subject = call_user_func($subjectEntityName . 'Entity::findPk', $report->subjectId); if ($subject->archived) { continue; } $this->saveReportData($getPeriodicSubjectData, $subjectEntityName, ['period' => $period, 'start' => $start, 'end' => $end], ['period' => $periodForecast, 'start' => $startForecast, 'end' => $endForecast], $report->subjectId, $report->subjectType, $report->emails, $formatedTitle); } else { if (!empty($report->subjectType)) { $subjects = call_user_func($subjectEntityName . 'Entity::find'); foreach ($subjects as $subject) { if ($subject->archived) { continue; } $this->saveReportData($getPeriodicSubjectData, $subjectEntityName, ['period' => $period, 'start' => $start, 'end' => $end], ['period' => $periodForecast, 'start' => $startForecast, 'end' => $endForecast], $subject->{$subjectId}, $report->subjectType, $report->emails, $formatedTitle); } } } } } $this->console->out('Done'); exit; }
/** * Gets parent Cost Center * * @return CostCentreEntity Returns cost centre entity */ public function getCostCenter() { if ($this->_cc === null || $this->_cc->ccId != $this->ccId) { $this->_cc = CostCentreEntity::findPk($this->ccId); } return $this->_cc; }
/** * @test */ public function textAccountComplex() { $ccsArch = $this->createCostCenter(['name' => $this->getTestName(), 'archived' => CostCentreEntity::ARCHIVED]); $ccs = $this->listCostCenters([], false); $adapter = $this->getAdapter('costCenter'); $filterable = $adapter->getRules()[ApiEntityAdapter::RULE_TYPE_FILTERABLE]; foreach ($ccs as $cc) { foreach ($filterable as $property) { $filterValue = $cc->{$property}; $listResult = $this->listCostCenters([$property => $filterValue], false); if (!static::isRecursivelyEmpty($filterValue)) { foreach ($listResult as $filtered) { $this->assertEquals($filterValue, $filtered->{$property}, "Property '{$property}' mismatch"); } } } $response = $this->getCostCenter($cc->id, false); $this->assertEquals(200, $response->status, $this->printResponseError($response)); /* @var $dbCc CostCentreEntity */ $dbCc = CostCentreEntity::findPk($cc->id); /* @var $acCs AccountCostCenterEntity */ $acCs = AccountCostCenterEntity::findOne([['ccId' => $dbCc->ccId]]); $this->assertFalse($dbCc->archived); $this->assertEquals($this->getUser()->accountId, $acCs->accountId); $this->assertObjectEqualsEntity($response->getBody()->data, $dbCc, $adapter); } $filterByName = $this->listCostCenters(['name' => $ccsArch->name], false); $this->assertNotEmpty($filterByName); foreach ($filterByName as $cc) { $this->assertObjectEqualsEntity($cc, $ccsArch, $adapter); $this->assertNotContains($cc, $ccs, "List of Cost Centers shouldn't have an archived project", false, false); } $filterByBillingCode = $this->listCostCenters(['billingCode' => $ccsArch->getProperty(CostCentrePropertyEntity::NAME_BILLING_CODE)], false); $this->assertNotEmpty($filterByBillingCode); foreach ($filterByBillingCode as $cc) { $this->assertObjectEqualsEntity($cc, $ccsArch, $adapter); $this->assertNotContains($cc, $ccs, "List of Cost Centers shouldn't have an archived project", false, false); } }
/** * xMoveProjectsAction * * @param JsonData $projects Projects that should be moved * @throws AnalyticsException * @throws Exception * @throws \Scalr\Exception\ModelException */ public function xMoveProjectsAction(JsonData $projects = null) { $envChange = []; $accountChange = []; $projectChange = []; $ccEntityCache = []; $collisions = []; foreach ($projects as $project) { $projectEntity = ProjectEntity::findPk($project['projectId']); /* @var $projectEntity ProjectEntity */ if (empty($ccEntity)) { $ccEntity = $projectEntity->getCostCenter(); } if ($ccEntity->ccId == $project['ccId']) { continue; } if (empty($ccEntityCache[$project['ccId']])) { $newCcEntity = CostCentreEntity::findPk($project['ccId']); /* @var $newCcEntity CostCentreEntity */ if (!$newCcEntity) { throw new Exception(sprintf("Cost center with id %s has not been found.", $project['ccId']), 404); } $ccEntityCache[$project['ccId']] = $newCcEntity->ccId; } $farms[$projectEntity->projectId] = $projectEntity->getFarmsList(); foreach ($farms[$projectEntity->projectId] as $farmId => $farmName) { $farmEntity = Farm::findPk($farmId); /* @var $farmEntity Farm */ if (empty($accountChange[$farmEntity->accountId])) { $accountCss = AccountCostCenterEntity::findOne([['accountId' => $farmEntity->accountId], ['ccId' => $newCcEntity->ccId]]); if (!$accountCss) { $accountChange[$farmEntity->accountId] = $newCcEntity->ccId; } } if (empty($envChange[$farmEntity->envId])) { $project['name'] = $projectEntity->name; $envChange[$farmEntity->envId] = $project; } else { if ($envChange[$farmEntity->envId]['ccId'] != $project['ccId']) { if (!in_array($projectEntity->name, $collisions)) { $collisions[] = $projectEntity->name; } if (!in_array($envChange[$farmEntity->envId]['name'], $collisions)) { $collisions[] = $envChange[$farmEntity->envId]['name']; } continue; } } } $projectEntity->ccId = $project['ccId']; $projectChange[$projectEntity->projectId] = $projectEntity; } $remainningEnvs = []; $projectsCount = count($projectChange); if ($projectsCount) { if (isset($ccEntity)) { $envList = $ccEntity->getEnvironmentsList(); foreach ($envList as $envId => $name) { if (isset($envChange[$envId])) { $ccProjects = $this->getContainer()->analytics->projects->getUsedInEnvironment($envId); foreach ($ccProjects as $project) { /* @var $project ProjectEntity */ if (!isset($farms[$project->projectId])) { $farms[$project->projectId] = $project->getFarmsList(); } if (count($farms[$project->projectId]) > 0 && !isset($projectChange[$project->projectId])) { if (!in_array($envId, $remainningEnvs)) { $remainningEnvs[] = $envId; } } } } } } $this->db->BeginTrans(); try { foreach ($accountChange as $accountId => $ccId) { $accountCss = new AccountCostCenterEntity($accountId, $ccId); $accountCss->save(); } if (empty($remainningEnvs) && empty($collisions)) { foreach ($envChange as $envId => $data) { $envProp = EnvironmentProperty::findOne([['envId' => $envId], ['name' => EnvironmentProperty::SETTING_CC_ID]]); /* @var $envProp EnvironmentProperty */ $envProp->value = $data['ccId']; $envProp->save(); } } foreach ($projectChange as $project) { /* @var $project ProjectEntity */ $project->save(); } $this->db->CommitTrans(); } catch (Exception $e) { $this->db->RollbackTrans(); throw $e; } } if (count($collisions) > 0) { $this->response->warning(sprintf("%d Project%s %s been moved however collision occurred. Projects '%s' are used in the Farms from the same Environment however they have been moved to different Cost Centers.", $projectsCount, $projectsCount > 1 ? 's' : '', $projectsCount > 1 ? 'have' : 'has', implode("', '", $collisions))); } else { if (count($remainningEnvs) > 0) { $this->response->warning(sprintf("%d Project%s %s been moved however some Projects don't correspond to Cost Centers assigned to Environments '%s'.", $projectsCount, $projectsCount > 1 ? 's' : '', $projectsCount > 1 ? 'have' : 'has', implode("', '", $remainningEnvs))); } else { $this->response->success(sprintf("%d Project%s %s been moved to other Cost Center.", $projectsCount, $projectsCount > 1 ? 's' : '', $projectsCount > 1 ? 'have' : 'has')); } } }
/** * Gets the list of the Cost Centers which correspond to Account * * @return \Scalr\Model\Collections\ArrayCollection Returns collection of the entities */ public function getCostCenters() { $ccs = new ArrayCollection(); foreach (AccountCostCenterEntity::findByAccountId($this->id) as $accountCc) { $cc = CostCentreEntity::findPk($accountCc->ccId); if (!$cc instanceof CostCentreEntity) { continue; } $ccs->append($cc); } return $ccs; }
public function applyGlobalVarsToValue($value) { if (empty($this->globalVariablesCache)) { $formats = \Scalr::config("scalr.system.global_variables.format"); $at = new Entity\Account\Team(); $ft = new Entity\FarmTeam(); $teams = Entity\Account\Team::find([\Scalr\Model\AbstractEntity::STMT_FROM => "{$at->table()} JOIN {$ft->table()} ON {$ft->columnTeamId} = {$at->columnId}", \Scalr\Model\AbstractEntity::STMT_WHERE => "{$ft->columnFarmId} = '{$this->ID}'"])->map(function ($t) { return $t->name; }); $systemVars = array('env_id' => $this->EnvID, 'env_name' => $this->GetEnvironmentObject()->name, 'farm_team' => join(",", $teams), 'farm_id' => $this->ID, 'farm_name' => $this->Name, 'farm_hash' => $this->Hash, 'farm_owner_email' => $this->createdByUserEmail); if (\Scalr::getContainer()->analytics->enabled) { $projectId = $this->GetSetting(Entity\FarmSetting::PROJECT_ID); if ($projectId) { $project = ProjectEntity::findPk($projectId); /* @var $project ProjectEntity */ $systemVars['project_id'] = $projectId; $systemVars['project_bc'] = $project->getProperty(ProjectPropertyEntity::NAME_BILLING_CODE); $systemVars['project_name'] = $project->name; $ccId = $project->ccId; } if ($ccId) { $cc = CostCentreEntity::findPk($ccId); if ($cc) { /* @var $cc CostCentreEntity */ $systemVars['cost_center_id'] = $ccId; $systemVars['cost_center_bc'] = $cc->getProperty(CostCentrePropertyEntity::NAME_BILLING_CODE); $systemVars['cost_center_name'] = $cc->name; } else { throw new Exception("Cost center {$ccId} not found"); } } } // Get list of Server system vars foreach ($systemVars as $name => $val) { $name = "SCALR_" . strtoupper($name); $val = trim($val); if (isset($formats[$name])) { $val = @sprintf($formats[$name], $val); } $this->globalVariablesCache[$name] = $val; } // Add custom variables $gv = new Scalr_Scripting_GlobalVariables($this->ClientID, $this->EnvID, ScopeInterface::SCOPE_FARM); $vars = $gv->listVariables(0, $this->ID); foreach ($vars as $v) { $this->globalVariablesCache[$v['name']] = $v['value']; } } //Parse variable $keys = array_keys($this->globalVariablesCache); $keys = array_map(function ($item) { return '{' . $item . '}'; }, $keys); $values = array_values($this->globalVariablesCache); $retval = str_replace($keys, $values, $value); // Strip undefined variables & return value return preg_replace("/{[A-Za-z0-9_-]+}/", "", $retval); }
/** * Creates default Cost Center for the Hosted Scalr new account * * @param Scalr_Account $account The account object * @param Scalr_Account_User $user optional The account owner user * @return CostCentreEntity Returns a new Cost Center */ public function createHostedScalrAccountCostCenter(Scalr_Account $account, Scalr_Account_User $user = null) { if (!$user instanceof Scalr_Account_User) { $user = $account->getOwner(); } //New Cost Center should be created in account share mode $cc = new CostCentreEntity(); $cc->ccId = \Scalr::GenerateUID(); $cc->accountId = $account->id; $cc->createdByEmail = $user->getEmail(); $cc->name = "Cost Center " . $account->name . " (" . $account->id . ")"; $cc->createdById = $user->id; $cc->save(); $cc->saveProperty(CostCentrePropertyEntity::NAME_BILLING_CODE, "CC-" . $account->name); $cc->saveProperty(CostCentrePropertyEntity::NAME_DESCRIPTION, "This Cost Center was added automatically."); $cc->saveProperty(CostCentrePropertyEntity::NAME_LEAD_EMAIL, $user->getEmail()); $cc->saveProperty(CostCentrePropertyEntity::NAME_LOCKED, false); //A new Project which corresponds to Cost Center (in account share mode as well) $project = new ProjectEntity(); $project->projectId = \Scalr::GenerateUID(); $project->ccId = $cc->ccId; $project->name = "Project " . $account->name . " (" . $account->id . ")"; $project->accountId = $account->id; $project->createdByEmail = $user->getEmail(); $project->shared = ProjectEntity::SHARED_WITHIN_ACCOUNT; $project->createdById = $user->id; $project->save(); $project->saveProperty(ProjectPropertyEntity::NAME_BILLING_CODE, "PR-" . $account->name); $project->saveProperty(ProjectPropertyEntity::NAME_DESCRIPTION, "This Project was added automatically."); $project->saveProperty(ProjectPropertyEntity::NAME_LEAD_EMAIL, $user->getEmail()); if (\Scalr::getContainer()->analytics->enabled) { \Scalr::getContainer()->analytics->tags->syncValue($account->id, TagEntity::TAG_ID_COST_CENTRE, $cc->ccId, $cc->name); \Scalr::getContainer()->analytics->tags->syncValue($account->id, TagEntity::TAG_ID_PROJECT, $project->projectId, $project->name); } return $cc; }
/** * xGetPeriodLogAction * * @param string $mode The mode (week, month, quarter, year) * @param string $startDate The start date of the period in UTC ('Y-m-d') * @param string $endDate The end date of the period in UTC ('Y-m-d') * @param string $type Type of the data gathered in log file (farms, clouds, projects) * @param string $ccId optional The identifier of the cost center * @param string $projectId optional The identifier of the project */ public function xGetPeriodCsvAction($mode, $startDate, $endDate, $type, $ccId = null, $projectId = null) { $name = 'Cloud'; if (!empty($ccId) && empty($projectId)) { $data = $this->getContainer()->analytics->usage->getCostCenterPeriodData($ccId, $mode, $startDate, $endDate); $entity = CostCentreEntity::findPk($ccId); if ($type !== 'clouds') { $name = 'Project'; $extraFields = 'Cost Center name;Billing code;Lead email address;'; } } else { if (!empty($projectId)) { $data = $this->getContainer()->analytics->usage->getProjectPeriodData($projectId, $mode, $startDate, $endDate); $entity = ProjectEntity::findPk($projectId); if ($type !== 'clouds') { $name = 'Farm'; $extraFields = 'Project name;Billing code;Lead email address;'; } } else { throw new \InvalidArgumentException(sprintf("Method %s requires both ccId or projectId to be specified.", __METHOD__)); } } $extraData = [$entity->name, $entity->getProperty('billing.code'), $entity->getProperty('lead.email')]; $head[] = $name; $end[] = "Total spent"; if (isset($extraFields)) { $head = array_merge($head, $extraData); $end = array_merge($end, $extraData); } $totals = 0; foreach ($data['timeline'] as $timeline) { $totals += $timeline['cost']; $head[] = $timeline['label']; $end[] = $timeline['cost']; } $head[] = 'Total'; $end[] = $totals; $temp = tmpfile(); fputcsv($temp, $head); foreach ($data[$type] as $item) { $row = []; $row[] = $item['name']; $dataCost = []; foreach ($data['timeline'] as $key => $value) { $dataCost[] = isset($item['data'][$key]['cost']) ? $item['data'][$key]['cost'] : 0; } $itemTotal = array_sum($dataCost); if (isset($extraFields)) { $row = array_merge($row, $extraData); } $row = array_merge($row, $dataCost); $row[] = $itemTotal; fputcsv($temp, $row); } fputcsv($temp, $end); $metadata = stream_get_meta_data($temp); $label = Scalr_Util_DateTime::convertTz(time(), 'M_j_Y_H:i:s'); $fileName = $entity->name . '.' . $entity->getProperty('billing.code') . '.' . $type . '.' . $label; $bad = array_merge(array_map('chr', range(0, 31)), ["<", ">", ":", '"', "/", "\\", "|", "?", "*"]); $fileName = str_replace($bad, "", $fileName); $this->response->setHeader('Content-Encoding', 'utf-8'); $this->response->setHeader('Content-Type', 'text/csv', true); $this->response->setHeader('Expires', 'Mon, 10 Jan 1997 08:00:00 GMT'); $this->response->setHeader('Pragma', 'no-cache'); $this->response->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate'); $this->response->setHeader('Cache-Control', 'post-check=0, pre-check=0'); $this->response->setHeader('Content-Disposition', 'attachment; filename=' . $fileName . ".csv"); $this->response->setResponse(file_get_contents($metadata['uri'])); fclose($temp); }
/** * Finds projects by key * It searches by name or billing number * * @param string $key optional Search key * @return ArrayCollection Returns collection of the ProjectEntity objects */ public function findByKey($key = null) { if (is_null($key) || $key === '') { return $this->all(); } $collection = new ArrayCollection(); $projectEntity = new ProjectEntity(); //Includes archived projects $projectPropertyEntity = new ProjectPropertyEntity(); //Cost center entity $ccEntity = new CostCentreEntity(); $rs = $this->db->Execute("\n SELECT " . $projectEntity->fields('p') . ", " . $ccEntity->fields('c', true) . "\n FROM " . $projectEntity->table('p') . "\n LEFT JOIN " . $ccEntity->table('c') . " ON c.`cc_id` = p.`cc_id`\n WHERE p.`name` LIKE ?\n OR EXISTS (\n SELECT 1 FROM " . $projectPropertyEntity->table('pp') . "\n WHERE `pp`.project_id = `p`.`project_id`\n AND `pp`.`name` = ? AND `pp`.`value` LIKE ?\n )\n ", ['%' . $key . '%', ProjectPropertyEntity::NAME_BILLING_CODE, '%' . $key . '%']); while ($rec = $rs->FetchRow()) { $item = new ProjectEntity(); $item->load($rec); if ($rec['c_cc_id']) { $cc = new CostCentreEntity(); $cc->load($rec, 'c'); $item->setCostCenter($cc); } $collection->append($item); } return $collection; }
protected function isApplied1($stage) { return CostCentreEntity::findPk(Usage::DEFAULT_CC_ID) !== null && ProjectEntity::findPk(Usage::DEFAULT_PROJECT_ID) !== null; }
protected function run7($stage) { if ($this->getCountOfAccountTagValues(TagEntity::TAG_ID_COST_CENTRE) && $this->console->confirm('Would you like to remove old cost centres from account_tag_values?')) { $this->console->out("Removing old cost centres"); $this->db->Execute("DELETE FROM account_tag_values WHERE tag_id = ?", array(TagEntity::TAG_ID_COST_CENTRE)); } $this->console->out('Populating cost centres to the dictionary'); foreach (CostCentreEntity::all() as $ccEntity) { /* @var $ccEntity CostCentreEntity */ $this->db->Execute("\n INSERT IGNORE `account_tag_values` (`account_id`, `tag_id`, `value_id`, `value_name`)\n VALUES (?, ?, ?, ?)\n ", [$ccEntity->accountId ?: 0, TagEntity::TAG_ID_COST_CENTRE, $ccEntity->ccId, $ccEntity->name]); } }
/** * * @return array */ public function GetScriptingVars() { $dbFarmRole = $this->GetFarmRoleObject(); $roleId = $dbFarmRole->RoleID; $dbRole = DBRole::loadById($roleId); $isDbMsr = $dbRole->getDbMsrBehavior(); if ($isDbMsr) { $isMaster = $this->GetProperty(Scalr_Db_Msr::REPLICATION_MASTER); } else { $isMaster = $this->GetProperty(\SERVER_PROPERTIES::DB_MYSQL_MASTER); } $retval = array('image_id' => $dbRole->__getNewRoleObject()->getImage($this->platform, $dbFarmRole->CloudLocation)->imageId, 'external_ip' => $this->remoteIp, 'internal_ip' => $this->localIp, 'role_name' => $dbRole->name, 'isdbmaster' => $isMaster, 'instance_index' => $this->index, 'instance_farm_index' => $this->farmIndex, 'server_type' => $this->type, 'server_hostname' => $this->GetProperty(Scalr_Role_Behavior::SERVER_BASE_HOSTNAME), 'server_id' => $this->serverId, 'farm_id' => $this->farmId, 'farm_role_id' => $this->farmRoleId, 'farm_role_alias' => $this->GetFarmRoleObject()->Alias, 'farm_name' => $this->GetFarmObject()->Name, 'farm_hash' => $this->GetFarmObject()->Hash, 'farm_owner_email' => $this->GetFarmObject()->createdByUserEmail, 'farm_team' => $this->GetFarmObject()->teamId ? (new Scalr_Account_Team())->loadById($this->GetFarmObject()->teamId)->name : '', 'behaviors' => implode(",", $dbRole->getBehaviors()), 'env_id' => $this->GetEnvironmentObject()->id, 'env_name' => $this->GetEnvironmentObject()->name, 'cloud_location' => $this->GetCloudLocation(), 'cloud_server_id' => $this->GetCloudServerID()); if ($this->cloudLocationZone) { $retval['cloud_location_zone'] = $this->cloudLocationZone; } if ($this->platform == SERVER_PLATFORMS::EC2) { $retval['instance_id'] = $this->GetProperty(EC2_SERVER_PROPERTIES::INSTANCE_ID); $retval['ami_id'] = $this->GetProperty(EC2_SERVER_PROPERTIES::AMIID); $retval['region'] = $this->GetProperty(EC2_SERVER_PROPERTIES::REGION); $retval['avail_zone'] = $this->GetProperty(EC2_SERVER_PROPERTIES::AVAIL_ZONE); if ($dbFarmRole->GetSetting(Entity\FarmRoleSetting::AWS_ELB_ENABLED)) { $elbId = $dbFarmRole->GetSetting(Entity\FarmRoleSetting::AWS_ELB_ID); $retval['aws_elb_name'] = $elbId; } } if (\Scalr::getContainer()->analytics->enabled) { $ccId = $this->GetProperty(\SERVER_PROPERTIES::ENV_CC_ID); if ($ccId) { $cc = CostCentreEntity::findPk($ccId); if ($cc) { /* @var $cc CostCentreEntity */ $retval['cost_center_id'] = $ccId; $retval['cost_center_bc'] = $cc->getProperty(CostCentrePropertyEntity::NAME_BILLING_CODE); $retval['cost_center_name'] = $cc->name; } else { throw new Exception("Cost center {$ccId} not found"); } } $projectId = $this->GetProperty(\SERVER_PROPERTIES::FARM_PROJECT_ID); if ($projectId) { $project = ProjectEntity::findPk($projectId); /* @var $project ProjectEntity */ $retval['project_id'] = $projectId; $retval['project_bc'] = $project->getProperty(ProjectPropertyEntity::NAME_BILLING_CODE); $retval['project_name'] = $project->name; } } return $retval; }
public function xSaveAction() { if (!$this->user->isAccountSuperAdmin() && !$this->request->isAllowed(Acl::RESOURCE_ENV_CLOUDS_ENVIRONMENT)) { throw new Scalr_Exception_InsufficientPermissions(); } $params = array('envId' => array('type' => 'int'), 'teams' => array('type' => 'json')); if ($this->user->isAccountOwner() || $this->user->isAccountSuperAdmin()) { $params['name'] = array('type' => 'string', 'validator' => array(Scalr_Validator::REQUIRED => true, Scalr_Validator::NOHTML => true)); } $this->request->defineParams($params); $this->request->validate(); if ($this->getContainer()->analytics->enabled) { if ($this->getParam('ccId')) { if (!$this->getContainer()->analytics->ccs->get($this->getParam('ccId'))) { $this->request->addValidationErrors('ccId', 'Invalid cost center ID'); } } else { $this->request->addValidationErrors('ccId', 'Cost center is required field'); } } if ($this->request->isValid()) { $isNew = false; if (!$this->getParam('envId')) { //create new environment if (!$this->user->isAccountOwner() && !$this->user->isAccountSuperAdmin()) { throw new Scalr_Exception_InsufficientPermissions(); } $this->user->getAccount()->validateLimit(Scalr_Limits::ACCOUNT_ENVIRONMENTS, 1); $env = $this->user->getAccount()->createEnvironment($this->getParam('name')); $isNew = true; } else { $env = Scalr_Environment::init()->loadById($this->getParam('envId')); } $this->user->getPermissions()->validate($env); if (!$this->user->isAccountSuperAdmin() && !$this->user->getAclRolesByEnvironment($env->id)->isAllowed(Acl::RESOURCE_ENV_CLOUDS_ENVIRONMENT)) { throw new Scalr_Exception_InsufficientPermissions(); } //set name, status and defaultPriority if ($this->user->isAccountOwner() || $this->user->isAccountSuperAdmin()) { $env->name = $this->getParam('name'); } if ($this->user->canManageAcl()) { $env->status = $this->getParam('status') == Scalr_Environment::STATUS_ACTIVE ? Scalr_Environment::STATUS_ACTIVE : Scalr_Environment::STATUS_INACTIVE; $env->defaultPriority = $this->getParam('defaultPriority'); } $env->save(); if ($this->user->canManageAcl()) { if ($this->getContainer()->analytics->enabled && $this->getParam('ccId')) { $oldCcId = $env->getPlatformConfigValue(Scalr_Environment::SETTING_CC_ID); $env->setPlatformConfig(array(Scalr_Environment::SETTING_CC_ID => $this->getParam('ccId'))); if ($isNew || $oldCcId != $this->getParam('ccId')) { $cc = CostCentreEntity::findPk($this->getParam('ccId')); $email = $cc->getProperty(CostCentrePropertyEntity::NAME_LEAD_EMAIL); $emailData = ['envName' => $env->name, 'ccName' => $cc->name]; if (!empty($email)) { \Scalr::getContainer()->mailer->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/analytics_on_cc_add.eml.php', $emailData, $email); } } if ($isNew || empty($oldCcId)) { $this->getContainer()->analytics->events->fireAssignCostCenterEvent($env, $this->getParam('ccId')); } elseif ($oldCcId != $this->getParam('ccId')) { $this->getContainer()->analytics->events->fireReplaceCostCenterEvent($env, $this->getParam('ccId'), $oldCcId); } } //set teams if ($this->getContainer()->config->get('scalr.auth_mode') == 'ldap') { $teams = array_map('trim', $this->getParam('teams')); $ldapGroups = null; if ($this->getContainer()->config->get('scalr.connections.ldap.user')) { $ldap = $this->getContainer()->ldap(null, null); $ldapGroups = $ldap->getGroupsDetails($teams); foreach ($teams as $team) { if (!isset($ldapGroups[$team])) { throw new \Exception(sprintf("Team '%s' is not found on the directory server", $team)); } } } $env->clearTeams(); foreach ($teams as $name) { $name = trim($name); if ($name) { $id = $this->db->GetOne('SELECT id FROM account_teams WHERE name = ? AND account_id = ? LIMIT 1', array($name, $this->user->getAccountId())); if (!$id) { $team = new Scalr_Account_Team(); $team->name = $name; $team->accountId = $this->user->getAccountId(); if ($ldapGroups !== null && $ldapGroups[$name] != $name) { $team->description = $ldapGroups[$name]; } $team->save(); $id = $team->id; } elseif ($ldapGroups !== null) { // Update team description $team = new Scalr_Account_Team(); $team->loadById($id); if ($team->description != $ldapGroups[$name] && $ldapGroups[$name] != $name) { $team->description = $ldapGroups[$name]; $team->save(); } } $env->addTeam($id); } } if ($this->getContainer()->config->get('scalr.connections.ldap.user')) { $user = strtok($this->user->getEmail(), '@'); $ldap = $this->getContainer()->ldap($user, null); if ($ldap->isValidUsername()) { $this->user->applyLdapGroups($ldap->getUserGroups()); } } } else { $env->clearTeams(); foreach ($this->getParam('teams') as $id) { $env->addTeam($id); } } } $this->response->success($isNew ? 'Environment successfully created' : 'Environment saved'); $env = Scalr_Environment::init()->loadById($env->id); //reload env to be sure we have actual params $teams = array(); foreach ($env->getTeams() as $teamId) { if ($this->getContainer()->config->get('scalr.auth_mode') == 'ldap') { $team = new Scalr_Account_Team(); $team->loadById($teamId); $teams[] = $team->name; } else { $teams[] = $teamId; } } $this->response->data(array('env' => array('id' => $env->id, 'name' => $env->name, 'status' => $env->status, 'defaultPriority' => $env->defaultPriority, 'platforms' => $env->getEnabledPlatforms(), 'teams' => $teams, 'ccId' => $env->getPlatformConfigValue(Scalr_Environment::SETTING_CC_ID)))); } else { $this->response->failure($this->request->getValidationErrorsMessage(), true); } }
/** * {@inheritdoc} * @see \Scalr\Model\AbstractEntity::save() */ public function save() { //Checks data integrity. $criteria = [['name' => $this->name]]; if ($this->ccId) { $criteria[] = ['ccId' => ['$ne' => $this->ccId]]; } //The name of the cost centre should be unique withing the global $item = CostCentreEntity::findOne($criteria); if ($item) { throw new AnalyticsException(sprintf('A Cost Center with this name already exists. Please choose another name.')); } parent::save(); if ($this->ccId && \Scalr::getContainer()->analytics->enabled) { \Scalr::getContainer()->analytics->tags->syncValue($this->accountId ?: 0, \Scalr\Stats\CostAnalytics\Entity\TagEntity::TAG_ID_COST_CENTRE, $this->ccId, $this->name); } }
public function xSaveAction() { $this->request->defineParams(array('ccId' => ['type' => 'string'], 'projectId' => ['type' => 'string'], 'year' => ['type' => 'int'], 'quarters' => ['type' => 'json'], 'selectedQuarter' => ['type' => 'string'])); $year = $this->getParam('year'); $selectedQuarter = $this->getParam('selectedQuarter'); if ($selectedQuarter !== 'year' && ($selectedQuarter < 1 || $selectedQuarter > 4)) { throw new OutOfBoundsException(sprintf("Invalid selectedQuarter number.")); } $quarterReq = []; foreach ($this->getParam('quarters') as $q) { if (!isset($q['quarter'])) { throw new InvalidArgumentException(sprintf("Missing quarter property for quarters data set in the request.")); } if ($q['quarter'] < 1 || $q['quarter'] > 4) { throw new OutOfRangeException(sprintf("Quarter value should be between 1 and 4.")); } if (!isset($q['budget'])) { throw new InvalidArgumentException(sprintf("Missing budget property for quarters data set in the request.")); } $quarterReq[$q['quarter']] = $q; } if ($this->getParam('projectId')) { $subjectType = QuarterlyBudgetEntity::SUBJECT_TYPE_PROJECT; $subjectId = $this->getParam('projectId'); } else { if ($this->getParam('ccId')) { $subjectType = QuarterlyBudgetEntity::SUBJECT_TYPE_CC; $subjectId = $this->getParam('ccId'); } else { throw new InvalidArgumentException(sprintf('Either ccId or projectId must be provided with the request.')); } } if (!preg_match("/^[[:xdigit:]-]{36}\$/", $subjectId)) { throw new InvalidArgumentException(sprintf("Invalid UUID has been passed.")); } if (!preg_match('/^\\d{4}$/', $year)) { throw new InvalidArgumentException(sprintf("Invalid year has been passed.")); } //Fetches the previous state of the entities from database if ($subjectType == QuarterlyBudgetEntity::SUBJECT_TYPE_CC) { $collection = QuarterlyBudgetEntity::getCcBudget($year, $subjectId); } else { $collection = QuarterlyBudgetEntity::getProjectBudget($year, $subjectId); } $quarters = new Quarters(SettingEntity::getQuarters(true)); //Updates|creates entities for ($quarter = 1; $quarter <= 4; ++$quarter) { if (!isset($quarterReq[$quarter])) { continue; } $period = $quarters->getPeriodForQuarter($quarter, $year); //Checks if period has already been closed and forbids update if ($period->end->format('Y-m-d') < gmdate('Y-m-d')) { continue; } $entity = current($collection->filterByQuarter($quarter)); if ($entity instanceof QuarterlyBudgetEntity) { //We should update an entity $entity->budget = abs((double) $quarterReq[$quarter]['budget']); } else { //We should create a new one. $entity = new QuarterlyBudgetEntity($year, $quarter); $entity->subjectType = $subjectType; $entity->subjectId = $subjectId; $entity->budget = abs((double) $quarterReq[$quarter]['budget']); } $entity->save(); } if ($selectedQuarter == 'year') { $selectedPeriod = $quarters->getPeriodForYear($year); } else { $selectedPeriod = $quarters->getPeriodForQuarter($selectedQuarter, $year); } if ($subjectType == QuarterlyBudgetEntity::SUBJECT_TYPE_PROJECT) { $data = $this->getProjectData(ProjectEntity::findPk($subjectId), $selectedPeriod, true); $budgetInfo = $this->getBudgetInfo($year, $data['ccId'], $data['projectId']); } else { $data = $this->getCostCenterData(CostCentreEntity::findPk($subjectId), $selectedPeriod); $budgetInfo = $this->getBudgetInfo($year, $subjectId); } $this->response->data(['data' => $data, 'budgetInfo' => $budgetInfo]); $this->response->success('Budget changes have been saved'); }
/** * Gets cost centre properties and parameters * * @param CostCentreEntity $cc Cost centre entity * @param string $calculate optional Whether response should be adjusted with cost usage data * @return array Returns cost centre properties and parameters */ private function getCostCenterData(CostCentreEntity $cc, $calculate = false) { $ret = array('ccId' => $cc->ccId, 'name' => $cc->name, 'billingCode' => $cc->getProperty(CostCentrePropertyEntity::NAME_BILLING_CODE), 'description' => $cc->getProperty(CostCentrePropertyEntity::NAME_DESCRIPTION), 'leadEmail' => $cc->getProperty(CostCentrePropertyEntity::NAME_LEAD_EMAIL), 'locked' => $cc->getProperty(CostCentrePropertyEntity::NAME_LOCKED) ? 1 : 0, 'created' => $cc->created->format('Y-m-d'), 'createdByEmail' => $cc->createdByEmail, 'archived' => $cc->archived, 'envCount' => count($cc->getEnvironmentsList()), 'projectsCount' => count($cc->getProjects())); if ($calculate) { $iterator = ChartPeriodIterator::create('month', gmdate('Y-m-01'), null, 'UTC'); $usage = $this->getContainer()->analytics->usage->get(['ccId' => $cc->ccId], $iterator->getStart(), $iterator->getEnd()); //It calculates usage for previous period same days $prevusage = $this->getContainer()->analytics->usage->get(['ccId' => $cc->ccId], $iterator->getPreviousStart(), $iterator->getPreviousEnd()); $ret = $this->getWrappedUsageData(['ccId' => $cc->ccId, 'iterator' => $iterator, 'usage' => $usage['cost'], 'prevusage' => $prevusage['cost']]) + $ret; } return $ret; }
/** * Initializes default cost centres and projects according to fixtures * * @return void */ public function initDefault() { $fixture = $this->fixture(); foreach ($fixture as $i => $c) { $ccId = key($c); $cc = CostCentreEntity::findPk($ccId); if (!$cc) { $cc = new CostCentreEntity(); $cc->ccId = $ccId; $cc->name = sprintf('Cost center %02d', $i + 1); $cc->save(); $cc->saveProperty(CostCentrePropertyEntity::NAME_DESCRIPTION, 'This is the automatically added cost center'); $cc->saveProperty(CostCentrePropertyEntity::NAME_BILLING_CODE, sprintf('CC-%02d', $i)); $cc->saveProperty(CostCentrePropertyEntity::NAME_LEAD_EMAIL, ''); $this->cadb->Execute("\n INSERT IGNORE `account_tag_values` (`account_id`, `tag_id`, `value_id`, `value_name`)\n VALUES (0, ?, ?, ?)\n ", [TagEntity::TAG_ID_COST_CENTRE, $cc->ccId, $cc->name]); } foreach ($fixture[$i][$ccId] as $j => $projectId) { $pr = ProjectEntity::findPk($projectId); if (!$pr) { $pr = new ProjectEntity(); $pr->projectId = $projectId; $pr->ccId = $ccId; $pr->name = sprintf('Project %d%d', $i, $j + 1); $pr->save(); $pr->saveProperty(ProjectPropertyEntity::NAME_DESCRIPTION, 'This is the automatically generated project'); $pr->saveProperty(ProjectPropertyEntity::NAME_BILLING_CODE, sprintf('PR-%02d-%02d', $i, $j)); $pr->saveProperty(ProjectPropertyEntity::NAME_LEAD_EMAIL, ''); $this->cadb->Execute("\n INSERT IGNORE `account_tag_values` (`account_id`, `tag_id`, `value_id`, `value_name`)\n VALUES (0, ?, ?, ?)\n ", [TagEntity::TAG_ID_PROJECT, $pr->projectId, $pr->name]); } } } //Assigns cost centre to each environment $res = $this->db->Execute("SELECT id FROM client_environments"); while ($rec = $res->FetchRow()) { try { $environment = \Scalr_Environment::init()->loadById($rec['id']); } catch (Exception $e) { continue; } $environment->setPlatformConfig(array(\Scalr_Environment::SETTING_CC_ID => $this->autoCostCentre($environment->id))); } //Assigns project to each farm $res = $this->db->Execute("SELECT id, env_id, clientid FROM farms"); while ($rec = $res->FetchRow()) { try { $dbFarm = DBFarm::LoadByID($rec['id']); } catch (Exception $e) { continue; } $dbFarm->SetSetting(DBFarm::SETTING_PROJECT_ID, $this->autoProject($dbFarm->EnvID, $dbFarm->ID)); } //Initializes servers properties $res = $this->db->Execute("\n SELECT DISTINCT s.server_id, s.env_id, s.farm_id\n FROM servers s\n LEFT JOIN server_properties p ON p.server_id = s.server_id AND p.name = ?\n LEFT JOIN server_properties p2 ON p2.server_id = s.server_id AND p2.name = ?\n WHERE p.server_id IS NULL OR p.`value` IS NULL\n OR (s.farm_id IS NOT NULL AND (p2.server_id IS NULL OR p2.`value` IS NULL))\n ", [SERVER_PROPERTIES::ENV_CC_ID, SERVER_PROPERTIES::FARM_PROJECT_ID]); while ($rec = $res->FetchRow()) { $ccid = $this->autoCostCentre($rec['env_id']); $this->db->Execute("\n INSERT `server_properties` (`server_id`, `name`, `value`)\n VALUE (?, ?, ?)\n ON DUPLICATE KEY UPDATE `value` = IFNULL(`value`, ?)\n ", [$rec['server_id'], SERVER_PROPERTIES::ENV_CC_ID, $ccid, $ccid]); //Farm may not exist for bundle task servers if ($rec['farm_id']) { $projectid = $this->autoProject($rec['env_id'], $rec['farm_id']); $this->db->Execute("\n INSERT `server_properties` (`server_id`, `name`, `value`)\n VALUE (?, ?, ?)\n ON DUPLICATE KEY UPDATE `value` = IFNULL(`value`, ?)\n ", [$rec['server_id'], SERVER_PROPERTIES::FARM_PROJECT_ID, $projectid, $projectid]); } } }
/** * Gets budget data for specified CC and period * * @param CostCentreEntity $cc * @param QuarterPeriod $period * @return array Returns budget data */ private function getCostCenterData(CostCentreEntity $cc, QuarterPeriod $period) { $ret = array('ccId' => $cc->ccId, 'name' => $cc->name, 'billingCode' => $cc->getProperty(CostCentrePropertyEntity::NAME_BILLING_CODE), 'description' => $cc->getProperty(CostCentrePropertyEntity::NAME_DESCRIPTION)); $budget = $this->getBudgetUsedPercentage(['ccId' => $cc->ccId, 'period' => $period, 'getRelationDependentBudget' => true]); foreach (['budget', 'budgetRemain', 'budgetRemainPct', 'budgetSpent', 'budgetSpentPct', 'budgetOverspend', 'budgetOverspendPct', 'relationDependentBudget'] as $field) { $ret[$field] = $budget[$field]; } return $ret; }
/** * Finds cost centres by key * It searches by name or billing number * * @param string $key optional Search key * @param array $criteria optional Search criteria * @param bool $ignoreCache optional Should it ignore cache or not * @return ArrayCollection Returns collection of the CostCentreEntity objects */ public function findByKey($key = null, $criteria = null, $ignoreCache = false) { if (is_null($key) || $key === '') { return $this->all(false, $criteria, $ignoreCache); } $collection = new ArrayCollection(); $ccEntity = new CostCentreEntity(); $ccPropertyEntity = new CostCentrePropertyEntity(); $projectEntity = new ProjectEntity(); $where = ''; $join = ''; $this->parseFindCriteria($criteria, $join, $where); $rs = $this->db->Execute("\n SELECT " . $ccEntity->fields('c') . "\n FROM " . $ccEntity->table('c') . " " . $join . "\n WHERE (c.`name` LIKE ?\n OR EXISTS (\n SELECT 1 FROM " . $ccPropertyEntity->table('cp') . "\n WHERE `cp`.cc_id = `c`.`cc_id`\n AND `cp`.`name` = ? AND `cp`.`value` LIKE ?\n ))\n " . $where . "\n ", ['%' . $key . '%', CostCentrePropertyEntity::NAME_BILLING_CODE, '%' . $key . '%']); while ($rec = $rs->FetchRow()) { $item = new CostCentreEntity(); $item->load($rec); $collection->append($item); } return $collection; }