diff --git a/modules/tracker/Notification.php b/modules/tracker/Notification.php index 700104137..ec84f3abb 100644 --- a/modules/tracker/Notification.php +++ b/modules/tracker/Notification.php @@ -23,7 +23,10 @@ /** * Notification manager for the tracker module. * + * @property Tracker_AggregateMetricModel $Tracker_AggregateMetric + * @property Tracker_AggregateMetricSpecModel $Tracker_AggregateMetricSpec * @property Tracker_ScalarModel $Tracker_Scalar + * @property Tracker_SubmissionModel $Tracker_Submission * @property Tracker_TrendModel $Tracker_Trend */ class Tracker_Notification extends ApiEnabled_Notification @@ -35,7 +38,7 @@ class Tracker_Notification extends ApiEnabled_Notification public $_models = array('User'); /** @var array */ - public $_moduleModels = array('Scalar', 'Trend', 'AggregateMetricSpec', 'AggregateMetric'); + public $_moduleModels = array('AggregateMetric', 'AggregateMetricNotification', 'AggregateMetricSpec', 'Scalar', 'Submission', 'Trend'); /** @var array */ public $_moduleComponents = array('Api'); @@ -94,7 +97,7 @@ public function communityDeleted($args) } /** - * When an item is deleted, we must delete associated item2scalar records. + * When an item is deleted, we must delete associated item2submission records. * * @todo * @param array $args associative array of parameters including the key "item" @@ -221,27 +224,37 @@ public function sendAggregateEmail($params) $userDao = $this->User->load($params['recipient_id']); if ($userDao === false) { $this->getLogger()->warn( - 'Attempting to send aggregate metric threshold notification to user id '.$params['recipientId'].': No such user.' + 'Attempting to send aggregate metric threshold notification to user id '.$params['recipient_id'].': No such user.' + ); + + return; + } + + /** @var Tracker_AggregateMetricDao $aggregateMetricDao */ + $aggregateMetricDao = $this->Tracker_AggregateMetric->load($params['aggregate_metric_id']); + if ($aggregateMetricDao === false) { + $this->getLogger()->warn( + 'Attempting to send aggregate metric threshold notification with aggregate metric '.$params['aggregate_metric_id'].': No such metric.' ); return; } /** @var Tracker_AggregateMetricSpecDao $aggregateMetricSpecDao */ - $aggregateMetricSpecDao = $this->Tracker_AggregateMetricSpec->load($params['aggregate_metric_spec_id']); + $aggregateMetricSpecDao = $aggregateMetricDao->getAggregateMetricSpec(); if ($aggregateMetricSpecDao === false) { $this->getLogger()->warn( - 'Attempting to send aggregate metric threshold notification with aggregate metric spec '.$params['aggregateMetricSpecId'].': No such spec.' + 'Attempting to send aggregate metric threshold notification with aggregate metric spec that does not exist.' ); return; } - /** @var Tracker_AggregateMetricDao $aggregateMetricDao */ - $aggregateMetricDao = $this->Tracker_AggregateMetric->load($params['aggregate_metric_id']); + /** @var Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao */ + $aggregateMetricNotificationDao = $this->Tracker_AggregateMetricNotification->load($params['aggregate_metric_notification_id']); if ($aggregateMetricDao === false) { $this->getLogger()->warn( - 'Attempting to send aggregate metric threshold notification with aggregate metric '.$params['aggregateMetricId'].': No such metric.' + 'Attempting to send aggregate metric threshold notification with aggregate metric notification id '.$params['aggregate_metric_notification_id'].': No such notification.' ); return; @@ -254,9 +267,9 @@ public function sendAggregateEmail($params) $producerName = $producerDao->getDisplayName(); $metricName = $aggregateMetricSpecDao->getName(); - $branch = $aggregateMetricSpecDao->getBranch(); - $thresholdValue = $aggregateMetricSpecDao->getValue(); - $thresholdComparison = $aggregateMetricSpecDao->getComparison(); + $thresholdValue = $aggregateMetricNotificationDao->getValue(); + $thresholdComparison = $aggregateMetricNotificationDao->getComparison(); + $branch = $aggregateMetricNotificationDao->getBranch(); $metricValue = $aggregateMetricDao->getValue(); $subject = 'Threshold Alert: '.$producerName.': '.$metricName; diff --git a/modules/tracker/configs/module.ini b/modules/tracker/configs/module.ini index 194489be5..7b5138fc9 100644 --- a/modules/tracker/configs/module.ini +++ b/modules/tracker/configs/module.ini @@ -6,4 +6,4 @@ description = "Track scalar results over time" category = "Visualization" dependencies = api,scheduler uuid = "3048a9fa-89ab-4e61-a55e-a49379fa6dc" -version = "1.2.4" +version = "2.0.1" diff --git a/modules/tracker/controllers/ProducerController.php b/modules/tracker/controllers/ProducerController.php index e3fc25dc7..f27eea86f 100644 --- a/modules/tracker/controllers/ProducerController.php +++ b/modules/tracker/controllers/ProducerController.php @@ -92,7 +92,7 @@ public function viewAction() } $this->view->producer = $producerDao; - $this->view->trendGroups = $this->Tracker_Trend->getTrendsGroupByDatasets($producerDao); + $this->view->trendGroups = $this->Tracker_Trend->getTrendsByGroup($producerDao); $this->view->isAdmin = $this->Tracker_Producer->policyCheck($producerDao, $this->userSession->Dao, MIDAS_POLICY_ADMIN); $this->view->json['tracker']['producer'] = $producerDao; diff --git a/modules/tracker/controllers/ScalarController.php b/modules/tracker/controllers/ScalarController.php index d5400f14a..5fe01149b 100644 --- a/modules/tracker/controllers/ScalarController.php +++ b/modules/tracker/controllers/ScalarController.php @@ -22,11 +22,12 @@ * Scalar controller for the tracker module. * * @property Tracker_ScalarModel $Tracker_Scalar + * @property Tracker_SubmissionModel $Tracker_Submission */ class Tracker_ScalarController extends Tracker_AppController { /** @var array */ - public $_moduleModels = array('Scalar'); + public $_moduleModels = array('Scalar', 'Submission'); /** * Display the dialog of scalar details, including associated result items with thumbnails. @@ -50,18 +51,23 @@ public function detailsAction() /** @var Tracker_ScalarDao $scalarDao */ $scalarDao = $this->Tracker_Scalar->load($scalarId); + /** @var Tracker_SubmissionDao $submissionDao */ + $submissionDao = $this->Tracker_Submission->load($scalarDao->getSubmissionId()); + if ($this->Tracker_Scalar->policyCheck($scalarDao, $this->userSession->Dao, MIDAS_POLICY_READ) === false ) { throw new Zend_Exception('The scalar does not exist or you do not have the necessary permission', 403); } $this->view->isAdmin = $this->Tracker_Scalar->policyCheck($scalarDao, $this->userSession->Dao, MIDAS_POLICY_ADMIN); + $this->view->scalar = $scalarDao; - $this->view->extraParams = $scalarDao->getParams(); - $this->view->extraUrls = json_decode($scalarDao->getExtraUrls(), true); + $this->view->submission = $submissionDao; + $this->view->extraParams = $submissionDao->getParams(); + $this->view->extraUrls = json_decode($submissionDao->getExtraUrls(), true); - $revisionUrl = $scalarDao->getTrend()->getProducer()->getRevisionUrl(); - $producerRevision = $scalarDao->getProducerRevision(); + $revisionUrl = $submissionDao->getProducer()->getRevisionUrl(); + $producerRevision = $submissionDao->getProducerRevision(); if (!is_null($revisionUrl)) { $producerRevisionUrl = preg_replace('/%revision/', $producerRevision, $revisionUrl); @@ -70,11 +76,10 @@ public function detailsAction() $this->view->revisionHtml = $producerRevision; } - $this->view->resultItems = $this->Tracker_Scalar->getAssociatedItems($scalarDao); - $this->view->otherValues = $this->Tracker_Scalar->getOtherValuesFromSubmission($scalarDao); + $this->view->otherValues = $this->Tracker_Submission->getValuesFromSubmission($submissionDao); - if ($scalarDao->getUserId() !== -1) { - $this->view->submittedBy = $scalarDao->getUser(); + if ($submissionDao->getUserId() !== -1) { + $this->view->submittedBy = $submissionDao->getUser(); } else { $this->view->submittedBy = null; } diff --git a/modules/tracker/controllers/TrendController.php b/modules/tracker/controllers/TrendController.php index 640807d1c..060156ba4 100644 --- a/modules/tracker/controllers/TrendController.php +++ b/modules/tracker/controllers/TrendController.php @@ -24,6 +24,8 @@ * @property Tracker_ScalarModel $Tracker_Scalar * @property Tracker_ThresholdNotificationModel $Tracker_ThresholdNotification * @property Tracker_TrendModel $Tracker_Trend + * @property Tracker_SubmissionModel $Tracker_Submission + * @property Tracker_ProducerModel $Tracker_Producer */ class Tracker_TrendController extends Tracker_AppController { @@ -31,7 +33,7 @@ class Tracker_TrendController extends Tracker_AppController public $_components = array('Breadcrumb'); /** @var array */ - public $_moduleModels = array('Producer', 'Scalar', 'ThresholdNotification', 'Trend'); + public $_moduleModels = array('Producer', 'Scalar', 'ThresholdNotification', 'Trend', 'Submission'); /** * View a given trend. @@ -81,7 +83,7 @@ public function viewAction() $userId = $this->userSession->Dao ? $this->userSession->Dao->getKey() : null; - $this->view->allBranches = $this->Tracker_Scalar->getDistinctBranches(); + $this->view->allBranches = $this->Tracker_Submission->getDistinctBranches(); $trendIds = explode(' ', trim(str_replace(',', ' ', $trendId))); $trendDaos = array(); @@ -104,7 +106,7 @@ public function viewAction() ); if (!isset($this->view->json['tracker']['producerId'])) { - $this->view->json['tracker']['producerId'] = $trendDao->getProducerId(); + $this->view->json['tracker']['producerId'] = $trendDao->getTrendgroup()->getProducerId(); } $trendDaos[] = $trendDao; @@ -112,7 +114,7 @@ public function viewAction() /** @var Tracker_TrendDao $trendDao */ $trendDao = $trendDaos[0]; - $producerDao = $trendDao->getProducer(); + $producerDao = $trendDao->getTrendgroup()->getProducer(); $communityDao = $producerDao->getCommunity(); if (count($trendDaos) === 1) { @@ -131,7 +133,7 @@ public function viewAction() /** @var Tracker_TrendDao $rightTrendDao */ $rightTrendDao = $this->Tracker_Trend->load($rightTrendId); - if ($communityDao !== false && $communityDao->getKey() !== $rightTrendDao->getProducer()->getCommunityId() + if ($communityDao !== false && $communityDao->getKey() !== $rightTrendDao->getTrendgroup()->getProducer()->getCommunityId() ) { throw new Zend_Exception('The right trend must belong to the same community as the other trends', 403); } @@ -555,8 +557,11 @@ public function setkeymetricAction() /** @var Tracker_TrendDao $trendDao */ $trendDao = $this->Tracker_Trend->load($trendId); + /** @var Tracker_TrendgroupDao $trendGroup */ + $trendGroup = $trendDao->getTrendgroup(); + /** @var Tracker_ProducerDao $producerDao */ - $producerDao = $trendDao->getProducer(); + $producerDao = $trendGroup->getProducer(); if ($this->Tracker_Producer->policyCheck($producerDao, $this->userSession->Dao, MIDAS_POLICY_ADMIN) === false ) { diff --git a/modules/tracker/controllers/api/AggregatemetricnotificationController.php b/modules/tracker/controllers/api/AggregatemetricnotificationController.php new file mode 100644 index 000000000..d2c697002 --- /dev/null +++ b/modules/tracker/controllers/api/AggregatemetricnotificationController.php @@ -0,0 +1,103 @@ +_genericAction( + $this->_request->getParams(), + $this->_request->getControllerName(), + $this->_request->getActionName(), + array('default' => $this->_request->getActionName()), + $this->moduleName, + false + ); + } + + /** Handle HTTP GET requests. Requires an id parameter. */ + public function getAction() + { + $this->_genericAction( + $this->_request->getParams(), + $this->_request->getControllerName(), + $this->_request->getActionName(), + array('default' => $this->_request->getActionName()), + $this->moduleName, + false + ); + } + + /** Handle HTTP HEAD requests. */ + public function headAction() + { + $this->_response->setHttpResponseCode(200); // 200 OK + } + + /** Handle HTTP GET index or list requests. */ + public function indexAction() + { + $this->_genericAction( + $this->_request->getParams(), + $this->_request->getControllerName(), + $this->_request->getActionName(), + array('default' => $this->_request->getActionName()), + $this->moduleName, + false + ); + } + + /** Handle HTTP OPTIONS requests. */ + public function optionsAction() + { + $this->_response->setHeader('Allow', 'DELETE, GET, HEAD, OPTIONS, POST, PUT'); + } + + /** Handle HTTP POST requests. */ + public function postAction() + { + $this->_genericAction( + $this->_request->getParams(), + $this->_request->getControllerName(), + $this->_request->getActionName(), + array('default' => $this->_request->getActionName()), + $this->moduleName, + false + ); + } + + /** Handle HTTP PUT requests. Requires an id parameter. */ + public function putAction() + { + $this->_genericAction( + $this->_request->getParams(), + $this->_request->getControllerName(), + $this->_request->getActionName(), + array('default' => $this->_request->getActionName()), + $this->moduleName, + false + ); + } +} diff --git a/modules/tracker/controllers/components/ApiComponent.php b/modules/tracker/controllers/components/ApiComponent.php index 76097bebc..93136b783 100644 --- a/modules/tracker/controllers/components/ApiComponent.php +++ b/modules/tracker/controllers/components/ApiComponent.php @@ -56,11 +56,14 @@ private function _getUser($args) } /** - * Associate a result item with a particular scalar value. + * Associate a result item with a particular submission. * - * @param scalarIds Comma separated list of scalar ids to associate the item with - * @param itemId The id of the item to associate with the scalar + * @param submissionUuid the uuid of the submission to associate the item with + * @param itemId The id of the item to associate with the submission * @param label The label describing the nature of the association + * @param testDatasetId (Optional) the id for the test dataset + * @param truthDatasetId (Optional) the id of the truth dataset + * @param configItemId (Optional) the id of the config dataset * @throws Exception */ public function itemAssociate($args) @@ -72,8 +75,12 @@ public function itemAssociate($args) $itemModel = MidasLoader::loadModel('Item'); /** @var Tracker_ScalarModel $scalarModel */ - $scalarModel = MidasLoader::loadModel('Scalar', 'tracker'); - $this->_checkKeys(array('scalarIds', 'itemId', 'label'), $args); + $submissionModel = MidasLoader::loadModel('Submission', 'tracker'); + + /** @var Tracker_TrendgroupModel $trendgroupModel */ + $trendgroupModel = MidasLoader::loadModel('Trendgroup', 'tracker'); + + $this->_checkKeys(array('submissionUuid', 'itemId', 'label'), $args); $user = $this->_getUser($args); /** @var ItemDao $item */ @@ -85,26 +92,36 @@ public function itemAssociate($args) throw new Exception('Read permission on the item required', 403); } - $scalarIds = explode(',', $args['scalarIds']); + $submissionUuid = $args['submissionUuid']; - /** @var int $scalarId */ - foreach ($scalarIds as $scalarId) { - /** @var Tracker_ScalarDao $scalar */ - $scalar = $scalarModel->load($scalarId); + /** @var Tracker_SubmissionDao $submission */ + $submission = $submissionModel->findBy('uuid', $submissionUuid); - if (!$scalar) { - throw new Exception('Invalid scalarId: '.$scalarId, 404); - } - if (!$communityModel->policyCheck( - $scalar->getTrend()->getProducer()->getCommunity(), - $user, - MIDAS_POLICY_ADMIN - ) - ) { - throw new Exception('Admin permission on the community required', 403); - } - $scalarModel->associateItem($scalar, $item, $args['label']); + if (!$submission) { + throw new Exception('Invalid submission uuid: '.$submissionUuid, 404); + } + + if (!$communityModel->policyCheck( + $submission->getProducer()->getCommunity(), + $user, + MIDAS_POLICY_WRITE + )) { + throw new Exception('Write permission on the community required', 403); } + + $configItemId = $args['configItemId']; + $testDatasetId = $args['testDatasetId']; + $truthDatasetId = $args['truthDatasetId']; + + /** @var Tracker_TrendgroupDao $trendgroup */ + $trendgroup = $trendgroupModel->createIfNeeded( + $submission->getProducer()->getKey(), + $configItemId, + $testDatasetId, + $truthDatasetId + ); + + $submissionModel->associateItem($submission, $item, $args['label'], $trendgroup); } /** @@ -113,22 +130,13 @@ public function itemAssociate($args) * @param communityId The id of the community that owns the producer * @param producerDisplayName The display name of the producer * @param metricName The metric name that identifies which trend this point belongs to - * @param producerRevision The repository revision of the producer that produced this value - * @param submitTime The submit timestamp. Must be parseable with PHP strtotime(). * @param value The value of the scalar - * @param submissionId (Optional) the id of the submission - * @param submissionUuid (Optional) the uuid of the submission - * @param buildResultsUrl (Optional) The URL where build results can be viewed - * @param extraUrls (Optional) JSON list of additional links - * @param params (Optional) JSON object of arbitrary key/value pairs to display - * @param branch (Optional) The branch name within the source repository + * @param submissionUuid the uuid of the submission. If a submission does not exist with the specified uuid, one + * will be created. * @param configItemId (Optional) If this value pertains to a specific configuration item, pass its id here * @param testDatasetId (Optional) If this value pertains to a specific test dataset, pass its id here * @param truthDatasetId (Optional) If this value pertains to a specific ground truth dataset, pass its id here - * @param silent (Optional) If set, do not perform threshold-based email notifications for this scalar - * @param unofficial (Optional) If passed, creates an unofficial scalar visible only to the user performing the submission * @param unit (Optional) If passed, the unit of the scalar value that identifies which trend this point belongs to. - * @param reproductionCommand (Optional) If passed, the command to produce this scalar * @return The scalar DAO that was created * @throws Exception */ @@ -140,19 +148,23 @@ public function scalarAdd($args) /** @var ItemModel $itemModel */ $itemModel = MidasLoader::loadModel('Item'); $this->_checkKeys( - array('communityId', 'producerDisplayName', 'metricName', 'value', 'producerRevision', 'submitTime'), + array( + 'communityId', + 'metricName', + 'producerDisplayName', + 'submissionUuid', + 'value', + ), $args ); $user = $this->_getUser($args); - $official = !array_key_exists('unofficial', $args); - /** @var CommunityDao $community */ $community = $communityModel->load($args['communityId']); if (!$community || !$communityModel->policyCheck( $community, $user, - $official ? MIDAS_POLICY_WRITE : MIDAS_POLICY_READ + MIDAS_POLICY_WRITE ) ) { throw new Exception('Write permission required on community', 403); @@ -230,21 +242,6 @@ public function scalarAdd($args) } } - if (isset($args['params'])) { - $extraParams = json_decode($args['params'], true); - } else { - $extraParams = null; - } - - if (isset($args['extraUrls'])) { - $extraUrls = json_decode($args['extraUrls'], true); - } else { - $extraUrls = null; - } - - $buildResultsUrl = isset($args['buildResultsUrl']) ? $args['buildResultsUrl'] : ''; - $branch = isset($args['branch']) ? $args['branch'] : ''; - if (isset($args['unit'])) { $unit = $args['unit']; } else { @@ -261,370 +258,19 @@ public function scalarAdd($args) $unit ); - $submitTime = strtotime($args['submitTime']); - if ($submitTime === false) { - throw new Exception('Invalid submitTime value: '.$args['submitTime'], -1); - } - $submitTime = date('Y-m-d H:i:s', $submitTime); - $value = (float) $args['value']; - $producerRevision = trim($args['producerRevision']); - - $submissionId = -1; - if (isset($args['submissionId'])) { - $submissionId = $args['submissionId']; - } elseif (isset($args['submissionUuid'])) { - $uuid = $args['submissionUuid']; - $submissionModel = MidasLoader::loadModel('Submission', 'tracker'); - $submissionDao = $submissionModel->getOrCreateSubmission($producer, $uuid); - $submissionId = $submissionDao->getKey(); - } - - $reproductionCommand = null; - if (isset($args['reproductionCommand'])) { - $reproductionCommand = $args['reproductionCommand']; - } + $uuid = $args['submissionUuid']; + $submissionModel = MidasLoader::loadModel('Submission', 'tracker'); + $submissionDao = $submissionModel->getOrCreateSubmission($producer, $uuid); /** @var Tracker_ScalarModel $scalarModel */ $scalarModel = MidasLoader::loadModel('Scalar', 'tracker'); - $scalar = $scalarModel->addToTrend( - $trend, - $submitTime, - $submissionId, - $producerRevision, - $value, - $user, - true, - $official, - $buildResultsUrl, - $branch, - $extraParams, - $extraUrls, - $reproductionCommand - ); - - if (!isset($args['silent'])) { - /** @var Tracker_ThresholdNotificationModel $notificationModel */ - $notificationModel = MidasLoader::loadModel('ThresholdNotification', 'tracker'); - $notifications = $notificationModel->getNotifications($scalar); - - /** @var Tracker_ThresholdNotificationComponent $notifyComponent */ - $notifyComponent = MidasLoader::loadComponent('ThresholdNotification', 'tracker'); - $notifyComponent->scheduleNotifications($scalar, $notifications); - } - if (!$official) { - /** @var Scheduler_JobModel $jobModel */ - $jobModel = MidasLoader::loadModel('Job', 'scheduler'); - - /** @var SettingModel $settingModel */ - $settingModel = MidasLoader::loadModel('Setting'); - $nHours = (int) $settingModel->getValueByName(MIDAS_TRACKER_TEMP_SCALAR_TTL_KEY, $this->moduleName); - if (!$nHours) { - $nHours = 24; // default to 24 hours - } - while (each($notifications)) { - /** @var Scheduler_JobDao $job */ - $job = MidasLoader::newDao('JobDao', 'scheduler'); - $job->setTask('TASK_TRACKER_DELETE_TEMP_SCALAR'); - $job->setPriority(1); - $job->setRunOnlyOnce(1); - $job->setFireTime(date('Y-m-d H:i:s', strtotime('+'.$nHours.' hours'))); - $job->setTimeInterval(0); - $job->setStatus(SCHEDULER_JOB_STATUS_TORUN); - $job->setCreatorId($user->getKey()); - $job->setParams(JsonComponent::encode(array('scalarId' => $scalar->getKey()))); - $jobModel->save($job); - } - } + $scalar = $scalarModel->addToTrend($trend, $submissionDao, $value); return $scalar; } - /** - * Upload a JSON file containing numeric scoring results to be added as scalars. File is parsed and then deleted from the server. - * - * @param communityId The id of the community that owns the producer - * @param producerDisplayName The display name of the producer - * @param producerRevision The repository revision of the producer that produced this value - * @param submitTime (Optional) The submit timestamp. Must be parseable with PHP strtotime(). If not set, uses current time. - * @param buildResultsUrl (Optional) The URL where build results can be viewed. - * @param branch (Optional) The branch name within the source repository - * @param extraUrls (Optional) JSON list of additional links - * @param params (Optional) JSON object of arbitrary key/value pairs to display - * @param configItemId (Optional) If this value pertains to a specific configuration item, pass its id here - * @param testDatasetId (Optional) If this value pertains to a specific test dataset, pass its id here - * @param truthDatasetId (Optional) If this value pertains to a specific ground truth dataset, pass its id here - * @param parentKeys (Optional) Semicolon-separated list of parent keys to look for numeric results under. Use '.' to denote nesting, like in normal JavaScript syntax. - * @param silent (Optional) If set, do not perform threshold-based email notifications for this scalar - * @param unofficial (Optional) If passed, creates an unofficial scalar visible only to the user performing the submission - * @return The list of scalars that were created. Non-numeric values are ignored. - * @throws Exception - */ - public function resultsUploadJson($args) - { - /** Change this to add a submission id or uuid. */ - $submissionId = -1; - /** @var CommunityModel $communityModel */ - $communityModel = MidasLoader::loadModel('Community'); - - /** @var ItemModel $itemModel */ - $itemModel = MidasLoader::loadModel('Item'); - $this->_checkKeys(array('communityId', 'producerDisplayName', 'producerRevision'), $args); - $user = $this->_getUser($args); - - $official = !array_key_exists('unofficial', $args); - if (!$official) { - /** @var Scheduler_JobModel $jobModel */ - $jobModel = MidasLoader::loadModel('Job', 'scheduler'); - - /** @var SettingModel $settingModel */ - $settingModel = MidasLoader::loadModel('Setting'); - $nHours = (int) $settingModel->getValueByName(MIDAS_TRACKER_TEMP_SCALAR_TTL_KEY, $this->moduleName); - if (!$nHours) { - $nHours = MIDAS_TRACKER_TEMP_SCALAR_TTL_DEFAULT_VALUE; // default to 24 hours - } - } - - // Unofficial submissions only require read access to the community - - /** @var CommunityDao $community */ - $community = $communityModel->load($args['communityId']); - if (!$community || !$communityModel->policyCheck( - $community, - $user, - $official ? MIDAS_POLICY_WRITE : MIDAS_POLICY_READ - ) - ) { - throw new Exception('Write permission required on community', 403); - } - - $producerDisplayName = trim($args['producerDisplayName']); - if ($producerDisplayName == '') { - throw new Exception('Producer display name must not be empty', -1); - } - - /** @var Tracker_ProducerModel $producerModel */ - $producerModel = MidasLoader::loadModel('Producer', 'tracker'); - $producer = $producerModel->createIfNeeded($community->getKey(), $producerDisplayName); - $buildResultsUrl = isset($args['buildResultsUrl']) ? $args['buildResultsUrl'] : ''; - $branch = isset($args['branch']) ? $args['branch'] : ''; - - list($configItemId, $testDatasetId, $truthDatasetId) = array(null, null, null); - if (isset($args['configItemId'])) { - /** @var int $configItemId */ - $configItemId = $args['configItemId']; - - /** @var ItemDao $configItem */ - $configItem = $itemModel->load($configItemId); - if (!$configItem || !$itemModel->policyCheck($configItem, $user, MIDAS_POLICY_READ) - ) { - throw new Exception('Read permission required on config item', 403); - } - } elseif (isset($args['configItemName'])) { - $configItem = $this->_createOrFindByName($args['configItemName'], $community); - $configItemId = $configItem->getKey(); - if (!$configItem || !$itemModel->policyCheck($configItem, $user, MIDAS_POLICY_READ) - ) { - throw new Exception('Read permission required on config item', 403); - } - } - - if (isset($args['testDatasetId'])) { - /** @var int $testDatasetId */ - $testDatasetId = $args['testDatasetId']; - - /** @var ItemDao $testDatasetItem */ - $testDatasetItem = $itemModel->load($testDatasetId); - if (!$testDatasetItem || !$itemModel->policyCheck($testDatasetItem, $user, MIDAS_POLICY_READ) - ) { - throw new Exception('Read permission required on test dataset item', 403); - } - } elseif (isset($args['testDatasetName'])) { - $testDatasetItem = $this->_createOrFindByName($args['testDatasetName'], $community); - $testDatasetId = $testDatasetItem->getKey(); - if (!$testDatasetItem || !$itemModel->policyCheck($testDatasetItem, $user, MIDAS_POLICY_READ) - ) { - throw new Exception('Read permission required on test dataset item', 403); - } - } - - if (isset($args['truthDatasetId'])) { - /** @var int $truthDatasetId */ - $truthDatasetId = $args['truthDatasetId']; - - /** @var ItemDao $truthDatasetItem */ - $truthDatasetItem = $itemModel->load($truthDatasetId); - if (!$truthDatasetItem || !$itemModel->policyCheck($truthDatasetItem, $user, MIDAS_POLICY_READ) - ) { - throw new Exception('Read permission required on truth dataset item', 403); - } - } elseif (isset($args['truthDatasetName'])) { - $truthDatasetItem = $this->_createOrFindByName($args['truthDatasetName'], $community); - $truthDatasetId = $truthDatasetItem->getKey(); - if (!$truthDatasetItem || !$itemModel->policyCheck($truthDatasetItem, $user, MIDAS_POLICY_READ) - ) { - throw new Exception('Read permission required on truth dataset item', 403); - } - } - - if (isset($args['params'])) { - $extraParams = json_decode($args['params'], true); - } else { - $extraParams = null; - } - - if (isset($args['extraUrls'])) { - $extraUrls = json_decode($args['extraUrls'], true); - } else { - $extraUrls = null; - } - - /** @var Tracker_TrendModel $trendModel */ - $trendModel = MidasLoader::loadModel('Trend', 'tracker'); - - if (isset($args['submitTime'])) { - $submitTime = strtotime($args['submitTime']); - if ($submitTime === false) { - throw new Exception('Invalid submitTime value: '.$args['submitTime'], -1); - } - $submitTime = date('Y-m-d H:i:s', $submitTime); - } else { - $submitTime = date('Y-m-d H:i:s'); // Use current time if no submit time is explicitly set - } - - $producerRevision = trim($args['producerRevision']); - - /** @var Tracker_ScalarModel $scalarModel */ - $scalarModel = MidasLoader::loadModel('Scalar', 'tracker'); - $json = json_decode(file_get_contents('php://input'), true); - if ($json === null) { - throw new Exception('Invalid JSON upload contents', -1); - } - $scalars = array(); - - if (isset($args['parentKeys'])) { // iterate through all child keys of the set of specified parent keys - $parentKeys = explode(';', $args['parentKeys']); - - /** @var string $parentKey */ - foreach ($parentKeys as $parentKey) { - $nodes = explode('.', $parentKey); - $currentArr = $json; - foreach ($nodes as $node) { - if (!isset($currentArr[$node]) || !is_array($currentArr[$node]) - ) { - throw new Exception( - 'Specified parent key "'.$parentKey.'" does not exist or is not an array type', -1 - ); - } - $currentArr = $currentArr[$node]; - } - - /** - * @var string $metricName - * @var float $value - */ - foreach ($currentArr as $metricName => $value) { // iterate through all children of this parent key - if (!is_numeric($value)) { // ignore non-numeric child keys - continue; - } - $trend = $trendModel->createIfNeeded( - $producer->getKey(), - $metricName, - $configItemId, - $testDatasetId, - $truthDatasetId - ); - $scalar = $scalarModel->addToTrend( - $trend, - $submitTime, - $submissionId, - $producerRevision, - $value, - $user, - true, - $official, - $buildResultsUrl, - $branch, - $extraParams, - $extraUrls - ); - $scalars[] = $scalar; - - if (!isset($args['silent'])) { - /** @var Tracker_ThresholdNotificationModel $notificationModel */ - $notificationModel = MidasLoader::loadModel('ThresholdNotification', 'tracker'); - $notifications = $notificationModel->getNotifications($scalar); - - /** @var Tracker_ThresholdNotificationComponent $notifyComponent */ - $notifyComponent = MidasLoader::loadComponent('ThresholdNotification', 'tracker'); - $notifyComponent->scheduleNotifications($scalar, $notifications); - } - if (!$official) { - while (each($notifications)) { - /** @var Scheduler_JobDao $job */ - $job = MidasLoader::newDao('JobDao', 'scheduler'); - $job->setTask('TASK_TRACKER_DELETE_TEMP_SCALAR'); - $job->setPriority(1); - $job->setRunOnlyOnce(1); - - /** @noinspection PhpUndefinedVariableInspection */ - $job->setFireTime(date('Y-m-d H:i:s', strtotime('+'.$nHours.' hours'))); - $job->setTimeInterval(0); - $job->setStatus(SCHEDULER_JOB_STATUS_TORUN); - $job->setCreatorId($user->getKey()); - $job->setParams(JsonComponent::encode(array('scalarId' => $scalar->getKey()))); - - /** @noinspection PhpUndefinedVariableInspection */ - $jobModel->save($job); - } - } - } - } - } else { // just read all the top level keys - - /** - * @var string $metricName - * @var float $value - */ - foreach ($json as $metricName => $value) { - if (!is_numeric($value)) { - continue; - } - $trend = $trendModel->createIfNeeded( - $producer->getKey(), - $metricName, - $configItemId, - $testDatasetId, - $truthDatasetId - ); - $scalar = $scalarModel->addToTrend( - $trend, - $submitTime, - $submissionId, - $producerRevision, - $value, - $user, - true, - $official - ); - $scalars[] = $scalar; - - if (!isset($args['silent'])) { - /** @var Tracker_ThresholdNotificationModel $notificationModel */ - $notificationModel = MidasLoader::loadModel('ThresholdNotification', 'tracker'); - $notifications = $notificationModel->getNotifications($scalar); - - /** @var Tracker_ThresholdNotificationComponent $notifyComponent */ - $notifyComponent = MidasLoader::loadComponent('ThresholdNotification', 'tracker'); - $notifyComponent->scheduleNotifications($scalar, $notifications); - } - } - } - - return $scalars; - } - /** * Create or find an item with the given name in the given community. * @@ -661,8 +307,17 @@ private function _createOrFindByName($itemName, $community) /** * Create a new submission. * - * @param uuid (Optional) A unique identifier for the submission + * @param producerRevision The repository revision of the producer that produced this value + * @param submitTime The submit timestamp. Must be parseable with PHP strtotime(). + * @param uuid (Optional) A unique identifier for the submission. If none is passed, one will be generated. * @param name (Optional) A name for the submission + * @param buildResultsUrl (Optional) The URL where build results can be viewed + * @param extraUrls (Optional) JSON list of additional links + * @param params (Optional) JSON object of arbitrary key/value pairs to display + * @param branch (Optional) The branch name within the source repository + * @param silent (Optional) If set, do not perform threshold-based email notifications for this scalar + * @param unofficial (Optional) If passed, creates an unofficial scalar visible only to the user performing the submission + * @param reproductionCommand (Optional) If passed, the command to produce this scalar * @return The submission DAO that was created * @throws Exception */ @@ -675,44 +330,6 @@ public function submissionAdd($args) return $newApi->post($args); } - /** - * Return an array of branch names from scalars tied to the producer - * and tied to trends with metric names matching the passed trend metric name. - * - * @param producerId The id of the producer tied to the scalars - * @param trendMetricName The metric_name of the trends tied to the scalars - * @return An array of branch names - * @throws Exception - */ - public function branchesformetricnameList($args) - { - $this->_checkKeys(array('producerId', 'trendMetricName'), $args); - $user = $this->_getUser($args); - - $producerId = $args['producerId']; - /** @var Tracker_ProducerModel $producerModel */ - $producerModel = MidasLoader::loadModel('Producer', 'tracker'); - /** @var Tracker_ProducerDao $producerDao */ - $producerDao = $producerModel->load($producerId); - /** @var CommunityDao $communityDao */ - $communityDao = $producerDao->getCommunity(); - - /** @var CommunityModel $communityModel */ - $communityModel = MidasLoader::loadModel('Community'); - if ($communityDao === false || $communityModel->policyCheck($communityDao, $user, MIDAS_POLICY_ADMIN) === false - ) { - throw new Zend_Exception('The associated community does not exist or you do not Admin access to the community', 403); - } - - $trendMetricName = $args['trendMetricName']; - /** @var Tracker_TrendModel $trendModel */ - $trendModel = MidasLoader::loadModel('Trend', 'tracker'); - /** @var array $branches */ - $branches = $trendModel->getDistinctBranchesForMetricName($producerId, $trendMetricName); - - return $branches; - } - /** * Update and return an array of all aggregate metrics calculated on each * aggregate metric spec attached to the submission identified by the passed in @@ -753,15 +370,12 @@ public function aggregatemetricsUpdate($args) $aggregateMetrics = $aggregateMetricModel->updateAggregateMetricsForSubmission($submissionDao); if (array_key_exists('notify', $args) && $args['notify']) { - /** @var Tracker_AggregateMetricSpecModel $aggregateMetricSpecModel */ - $aggregateMetricSpecModel = MidasLoader::loadModel('AggregateMetricSpec', 'tracker'); - /** @var Tracker_ThresholdNotificationComponent $notifyComponent */ - $notifyComponent = MidasLoader::loadComponent('ThresholdNotification', 'tracker'); + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', 'tracker'); /** @var Tracker_AggregateMetricDao $aggregateMetricDao */ foreach ($aggregateMetrics as $aggregateMetricDao) { - /* @var Tracker_AggregateMetricSpecDao $aggregateMetricSpecDao */ - $aggregateMetricSpecDao = $aggregateMetricDao->getAggregateMetricSpec(); - $notificationJobs = $aggregateMetricSpecModel->scheduleNotificationJobs($aggregateMetricSpecDao, $aggregateMetricDao); + /* @var array $notificationJobs */ + $notificationJobs = $aggregateMetricNotificationModel->scheduleNotificationJobs($aggregateMetricDao); } } @@ -792,85 +406,103 @@ private function _loadAggregateMetricSpec($userDao, $aggregateMetricSpecId, $pol } /** - * Create a notification for a user against an aggregate metric spec, so that - * whenever an aggregate metric created from that aggregate metric spec + * Create a notification for a user against an aggregate metric notification, + * so that whenever an aggregate metric created from that aggregate metric spec * is beyond the notification threshold, the user will be notified by email. * - * @param userId The id of the user to create a notification for - * @param aggregateMetricSpecId The id of the aggregate metric spec + * @param userId The id of the user to tie to the notification + * @param aggregateMetricNotificationId The id of the aggregate metric notification * @return UserDao the user DAO of the user who will be alerted * @throws Exception */ public function aggregatemetricspecnotifieduserCreate($args) { - $this->_checkKeys(array('userId', 'aggregateMetricSpecId'), $args); + $this->_checkKeys(array('userId', 'aggregateMetricNotificationId'), $args); $user = $this->_getUser($args); - $aggregateMetricSpecId = $args['aggregateMetricSpecId']; - $aggregateMetricSpecDao = $this->_loadAggregateMetricSpec($user, $aggregateMetricSpecId, MIDAS_POLICY_ADMIN); + $aggregateMetricNotificationId = $args['aggregateMetricNotificationId']; + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', 'tracker'); + /** @var Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao */ + $aggregateMetricNotificationDao = $aggregateMetricNotificationModel->load($aggregateMetricNotificationId); + + /** @var Tracker_AggregateMetricSpecDao $aggregateMetricSpecDao */ + $aggregateMetricSpecDao = $this->_loadAggregateMetricSpec($user, $aggregateMetricNotificationDao->getAggregateMetricSpecId(), MIDAS_POLICY_ADMIN); /** @var UserModel $userModel */ $userModel = MidasLoader::loadModel('User'); /** @var UserDao $notificationUserDao */ $notificationUserDao = $userModel->load($args['userId']); - /** @var Tracker_AggregateMetricSpecModel $aggregateMetricSpecModel */ - $aggregateMetricSpecModel = MidasLoader::loadModel('AggregateMetricSpec', 'tracker'); - $aggregateMetricSpecModel->createUserNotification($aggregateMetricSpecDao, $notificationUserDao); + $aggregateMetricNotificationModel->createUserNotification($aggregateMetricNotificationDao, $notificationUserDao); return $notificationUserDao; } /** - * Delete a notification for a user against an aggregate metric spec, so that - * the user will no longer receive notifications from aggregate metrics created - * from that aggregate metric spec. + * Delete a user from an aggregate metric notification, + * the user will no longer receive notifications when aggregate metrics created + * from the associated aggregate metric spec are beyond the notification threshold of the + * notification. * - * @param userId The id of the user to delete a notification for - * @param aggregateMetricSpecId The id of the aggregate metric spec + * @param userId The id of the user to delete from the notification + * @param aggregateMetricNotificationId The id of the aggregate metric notification * @return UserDao the user DAO of the user who will no longer be alerted * @throws Exception */ public function aggregatemetricspecnotifieduserDelete($args) { - $this->_checkKeys(array('userId', 'aggregateMetricSpecId'), $args); + $this->_checkKeys(array('userId', 'aggregateMetricNotificationId'), $args); $user = $this->_getUser($args); - $aggregateMetricSpecId = $args['aggregateMetricSpecId']; - $aggregateMetricSpecDao = $this->_loadAggregateMetricSpec($user, $aggregateMetricSpecId, MIDAS_POLICY_ADMIN); + $aggregateMetricNotificationId = $args['aggregateMetricNotificationId']; + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', 'tracker'); + /** @var Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao */ + $aggregateMetricNotificationDao = $aggregateMetricNotificationModel->load($aggregateMetricNotificationId); + + /** @var Tracker_AggregateMetricSpecDao $aggregateMetricSpecDao */ + $aggregateMetricSpecDao = $this->_loadAggregateMetricSpec($user, $aggregateMetricNotificationDao->getAggregateMetricSpecId(), MIDAS_POLICY_ADMIN); /** @var UserModel $userModel */ $userModel = MidasLoader::loadModel('User'); /** @var UserDao $notificationUserDao */ $notificationUserDao = $userModel->load($args['userId']); - /** @var Tracker_AggregateMetricSpecModel $aggregateMetricSpecModel */ - $aggregateMetricSpecModel = MidasLoader::loadModel('AggregateMetricSpec', 'tracker'); - $aggregateMetricSpecModel->deleteUserNotification($aggregateMetricSpecDao, $notificationUserDao); + $aggregateMetricNotificationModel->deleteUserNotification($aggregateMetricNotificationDao, $notificationUserDao); return $notificationUserDao; } /** - * Return a list of User Daos for all users with notifications on this aggregate metric spec. + * Return an array of associative arrays, with keys 'notification' => an AggregateMetricNotificationDao + * and 'users' => an array of UserDaos tied to the AggregateMetricNotificationDao, for each + * AggregateMetricNotification tied to the passed in AggregateMetricSpecId. * * @param aggregateMetricSpecId the id of the aggregate metric spec - * @return array of UserDao for all users with notification on the passed in aggregateMetricSpecId + * @return array of associative arrays with keys 'notification' and 'users' */ - public function aggregatemetricspecnotifiedusersList($args) + public function aggregatemetricspecnotificationsList($args) { $this->_checkKeys(array('aggregateMetricSpecId'), $args); $user = $this->_getUser($args); + /** @var Tracker_AggregateMetricSpecDao $aggregateMetricSpecDao */ $aggregateMetricSpecDao = $this->_loadAggregateMetricSpec($user, $args['aggregateMetricSpecId']); - /** @var Tracker_AggregateMetricSpecModel $aggregateMetricSpecModel */ - $aggregateMetricSpecModel = MidasLoader::loadModel('AggregateMetricSpec', 'tracker'); - $notifiedUsers = $aggregateMetricSpecModel->getAllNotifiedUsers($aggregateMetricSpecDao); - if ($notifiedUsers === false) { - $notifiedUsers = array(); + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', 'tracker'); + /** @var array $notifications */ + $notifications = $aggregateMetricNotificationModel->findBy('aggregate_metric_spec_id', $aggregateMetricSpecDao->getAggregateMetricSpecId()); + $response = array(); + /** @var Tracker_AggregateMetricNotificationDao $notification */ + foreach ($notifications as $notification) { + $response[] = array( + 'notification' => $notification, + 'users' => $aggregateMetricNotificationModel->getAllNotifiedUsers($notification), + ); } - return $notifiedUsers; + return $response; } } diff --git a/modules/tracker/controllers/components/ApiaggregatemetricnotificationComponent.php b/modules/tracker/controllers/components/ApiaggregatemetricnotificationComponent.php new file mode 100644 index 000000000..86d2ee2bc --- /dev/null +++ b/modules/tracker/controllers/components/ApiaggregatemetricnotificationComponent.php @@ -0,0 +1,232 @@ +validateParams($args, array('id')); + $apihelperComponent->requirePolicyScopes(array(MIDAS_API_PERMISSION_SCOPE_ADMIN_DATA)); + + /** @var int $aggregateMetricNotificationId */ + $aggregateMetricNotificationId = $args['id']; + + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', $this->moduleName); + /** @var Tracker_AggregateMetricSpecModel $aggregateMetricSpecModel */ + $aggregateMetricSpecModel = MidasLoader::loadModel('AggregateMetricSpec', $this->moduleName); + + /** @var Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao */ + $aggregateMetricNotificationDao = $aggregateMetricNotificationModel->load($aggregateMetricNotificationId); + $userDao = $apihelperComponent->getUser($args); + if ($aggregateMetricSpecModel->policyCheck($aggregateMetricNotificationDao->getAggregateMetricSpec(), $userDao, MIDAS_POLICY_WRITE) === false) { + throw new Exception('The aggregateMetricNotification does not exist or you do not have the necessary permission', MIDAS_INVALID_POLICY); + } + + $aggregateMetricNotificationModel->delete($aggregateMetricNotificationDao); + } + + /** + * Retrieve the given aggregateMetricNotification. + * + * @path /tracker/aggregatemetricnotification/{id} + * @http GET + * @param id + * @return array + * + * @param array $args parameters + * @throws Exception + */ + public function get($args) + { + /** @var ApihelperComponent $apihelperComponent */ + $apihelperComponent = MidasLoader::loadComponent('Apihelper'); + $apihelperComponent->validateParams($args, array('id')); + $apihelperComponent->requirePolicyScopes(array(MIDAS_API_PERMISSION_SCOPE_READ_DATA)); + + /** @var int $aggregateMetricNotificationId */ + $aggregateMetricNotificationId = $args['id']; + + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', $this->moduleName); + /** @var Tracker_AggregateMetricSpecModel $aggregateMetricSpecModel */ + $aggregateMetricSpecModel = MidasLoader::loadModel('AggregateMetricSpec', $this->moduleName); + + /** @var Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao */ + $aggregateMetricNotificationDao = $aggregateMetricNotificationModel->load($aggregateMetricNotificationId); + $userDao = $apihelperComponent->getUser($args); + if ($aggregateMetricSpecModel->policyCheck($aggregateMetricNotificationDao->getAggregateMetricSpec(), $userDao, MIDAS_POLICY_READ) === false) { + throw new Exception('The aggregateMetricNotification does not exist or you do not have the necessary permission', MIDAS_INVALID_POLICY); + } + + return $this->_toArray($aggregateMetricNotificationDao); + } + + /** + * TODO. + * + * @path /tracker/aggregatemetricnotification/{id} + * @http GET + * @return array + * + * @param array $args parameters + * @throws Exception + */ + public function index($args) + { + /** @var ApihelperComponent $apihelperComponent */ + $apihelperComponent = MidasLoader::loadComponent('Apihelper'); + $apihelperComponent->validateParams($args, array()); + $apihelperComponent->requirePolicyScopes(array(MIDAS_API_PERMISSION_SCOPE_READ_DATA)); + + // TODO: Implement index(). + + return array(); + } + + /** + * Create a new aggregateMetricNotification. + * + * @path /tracker/aggregatemetricnotification + * @http POST + * @param aggregate_metric_spec_id + * @param branch + * @param comparison + * @param value + * @return array + * + * @param array $args parameters + * @throws Exception + */ + public function post($args) + { + /** @var ApihelperComponent $apihelperComponent */ + $apihelperComponent = MidasLoader::loadComponent('Apihelper'); + $apihelperComponent->validateParams($args, array('aggregate_metric_spec_id', 'branch', 'comparison', 'value')); + $apihelperComponent->requirePolicyScopes(array(MIDAS_API_PERMISSION_SCOPE_WRITE_DATA)); + + /** @var int $aggregateMetricSpecId */ + $aggregateMetricSpecId = $args['aggregate_metric_spec_id']; + + /** @var Tracker_AggregateMetricSpecModel $aggregateMetricSpecModel */ + $aggregateMetricSpecModel = MidasLoader::loadModel('AggregateMetricSpec', $this->moduleName); + + /** @var Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao */ + $aggregateMetricSpecDao = $aggregateMetricSpecModel->load($aggregateMetricSpecId); + $userDao = $apihelperComponent->getUser($args); + if ($aggregateMetricSpecModel->policyCheck($aggregateMetricSpecDao, $userDao, MIDAS_POLICY_WRITE) === false) { + throw new Exception('The aggregateMetricSpec does not exist or you do not have the necessary permission', MIDAS_INVALID_POLICY); + } + + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', $this->moduleName); + /** @var Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao */ + $aggregateMetricNotificationDao = $aggregateMetricNotificationModel->initDao('AggregateMetricNotification', $args, $this->moduleName); + $aggregateMetricNotificationModel->save($aggregateMetricNotificationDao); + + return $this->_toArray($aggregateMetricNotificationDao); + } + + /** + * Update the given aggregateMetricNotification. + * + * @path /tracker/aggregatemetricnotification/{id} + * @http PUT + * @param id + * @param branch(Optional) + * @param value (Optional) + * @param comparison (Optional) + * @return array + * + * @param array $args parameters + * @throws Exception + */ + public function put($args) + { + /** @var ApihelperComponent $apihelperComponent */ + $apihelperComponent = MidasLoader::loadComponent('Apihelper'); + $apihelperComponent->validateParams($args, array('id')); + $apihelperComponent->requirePolicyScopes(array(MIDAS_API_PERMISSION_SCOPE_WRITE_DATA)); + + /** @var int $aggregateMetricNotificationId */ + $aggregateMetricNotificationId = $args['id']; + + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', $this->moduleName); + /** @var Tracker_AggregateMetricSpecModel $aggregateMetricSpecModel */ + $aggregateMetricSpecModel = MidasLoader::loadModel('AggregateMetricSpec', $this->moduleName); + + /** @var Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao */ + $aggregateMetricNotificationDao = $aggregateMetricNotificationModel->load($aggregateMetricNotificationId); + $userDao = $apihelperComponent->getUser($args); + if ($aggregateMetricSpecModel->policyCheck($aggregateMetricNotificationDao->getAggregateMetricSpec(), $userDao, MIDAS_POLICY_WRITE) === false) { + throw new Exception('The aggregateMetricNotification does not exist or you do not have the necessary permission', MIDAS_INVALID_POLICY); + } + + // Disallow modification of the aggregate_metric_spec_id. + if (isset($args['aggregate_metric_spec_id'])) { + unset($args['aggregate_metric_spec_id']); + } + + /** @var string $name */ + /** @var mixed $option */ + foreach ($aggregateMetricNotificationModel->getMainData() as $name => $option) { + if (isset($args[$name])) { + $aggregateMetricNotificationDao->$name = $args[$name]; + } + } + $aggregateMetricNotificationModel->save($aggregateMetricNotificationDao); + + return $this->_toArray($aggregateMetricNotificationDao); + } + + /** + * Convert the given aggregateMetricNotification DAO to an array and prepend metadata. + * + * @param Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao aggregateMetricNotification DAO + * @return array associative array representation of the aggregateMetricNotification DAO with metadata prepended + */ + protected function _toArray($aggregateMetricNotificationDao) + { + $aggregateMetricNotificationArray = array( + '_id' => $aggregateMetricNotificationDao->getKey(), + '_type' => 'Tracker_AggregateMetricNotification', + ); + + return array_merge($aggregateMetricNotificationArray, $aggregateMetricNotificationDao->toArray()); + } +} diff --git a/modules/tracker/controllers/components/ApiaggregatemetricspecComponent.php b/modules/tracker/controllers/components/ApiaggregatemetricspecComponent.php index eb967579f..537636a5f 100644 --- a/modules/tracker/controllers/components/ApiaggregatemetricspecComponent.php +++ b/modules/tracker/controllers/components/ApiaggregatemetricspecComponent.php @@ -122,12 +122,9 @@ public function index($args) * @path /tracker/aggregatemetricspec * @http POST * @param producer_id - * @param branch * @param name * @param spec * @param description (Optional) - * @param value (Optional) - * @param comparison (Optional) * @return array * * @param array $args parameters @@ -171,12 +168,9 @@ public function post($args) * @http PUT * @param id * @param producer_id (Optional) - * @param branch (Optional) * @param name (Optional) * @param spec (Optional) * @param description (Optional) - * @param value (Optional) - * @param comparison (Optional) * @return array * * @param array $args parameters diff --git a/modules/tracker/controllers/components/ApiscalarComponent.php b/modules/tracker/controllers/components/ApiscalarComponent.php index 5023abecd..3f71f9980 100644 --- a/modules/tracker/controllers/components/ApiscalarComponent.php +++ b/modules/tracker/controllers/components/ApiscalarComponent.php @@ -121,16 +121,8 @@ public function index($args) * @path /tracker/scalar * @http POST * @param trend_id - * @param submission_id (Optional) - * @param user_id (Optional) - * @param official (Optional) - * @param build_results_url (Optional) - * @param params (Optional) - * @param extra_urls (Optional) - * @param branch (Optional) - * @param submit_time (Optional) - * @param value (Optional) - * @param producer_revision (Optional) + * @param submission_id + * @param value * @return array * * @param array $args parameters @@ -157,14 +149,6 @@ public function post($args) throw new Exception('The trend does not exist or you do not have the necessary permission', MIDAS_INVALID_POLICY); } - if (isset($args['params']) && !is_null($args['params']) && !is_string($args['params'])) { - $args['params'] = json_encode($args['params']); - } - - if (isset($args['extra_urls']) && !is_null($args['extra_urls']) && !is_string($args['extra_urls'])) { - $args['extra_urls'] = json_encode($args['extra_urls']); - } - /** @var Tracker_ScalarModel $scalarModel */ $scalarModel = MidasLoader::loadModel('Scalar', $this->moduleName); @@ -186,15 +170,7 @@ public function post($args) * @param id * @param trend_id * @param submission_id (Optional) - * @param user_id (Optional) - * @param official (Optional) - * @param build_results_url (Optional) - * @param params (Optional) - * @param extra_urls (Optional) - * @param branch (Optional) - * @param submit_time (Optional) * @param value (Optional) - * @param producer_revision (Optional) * @return array * * @param array $args parameters @@ -221,33 +197,11 @@ public function put($args) throw new Exception('The scalar does not exist or you do not have the necessary permission', MIDAS_INVALID_POLICY); } - if (isset($args['params']) && !is_null($args['params'])) { - $params = $args['params']; - unset($args['params']); - } - - if (isset($args['extra_urls']) && !is_null($args['extra_urls']) && !is_string($args['extra_urls'])) { - $args['extra_urls'] = json_encode($args['extra_urls']); - } - /** @var Tracker_ScalarDao $scalarDao */ $scalarDao = $scalarModel->initDao('Scalar', $args, $this->moduleName); $scalarDao->setScalarId($scalarId); $scalarModel->save($scalarDao); - if (isset($params) && is_string($params)) { - $params = json_decode($params); - $paramModel = MidasLoader::loadModel('Param', $this->moduleName); - foreach ($params as $paramName => $paramValue) { - /** @var Tracker_ParamDao $paramDao */ - $paramDao = MidasLoader::newDao('ParamDao', $this->moduleName); - $paramDao->setScalarId($scalarDao->getScalarId()); - $paramDao->setParamName($paramName); - $paramDao->setParamValue($paramValue); - $paramModel->save($paramDao); - } - } - /** @var Tracker_ScalarDao $scalarDao */ $scalarDao = $scalarModel->load($scalarId); diff --git a/modules/tracker/controllers/components/ApisubmissionComponent.php b/modules/tracker/controllers/components/ApisubmissionComponent.php index ff02b76bd..e515fd74a 100644 --- a/modules/tracker/controllers/components/ApisubmissionComponent.php +++ b/modules/tracker/controllers/components/ApisubmissionComponent.php @@ -129,9 +129,17 @@ public function index($args) * * @path /tracker/submission * @http POST - * @param producer_id + * @param communityId + * @param producerDisplayName + * @param producerRevision * @param uuid (Optional) * @param name (Optional) + * @param submitTime (Optional) + * @param branch (Optional) + * @param buildResultsUrl (Optional) + * @param params (Optional) + * @param extraUrls (Optional) + * @param reproductionCommand (Optional) * @return array * * @param array $args parameters @@ -143,7 +151,7 @@ public function post($args) $apihelperComponent = MidasLoader::loadComponent('Apihelper'); $apihelperComponent->requirePolicyScopes( array(MIDAS_API_PERMISSION_SCOPE_WRITE_DATA)); - $apihelperComponent->validateParams($args, array('producer_id')); + $apihelperComponent->validateParams($args, array('communityId', 'producerDisplayName', 'producerRevision')); $this->_checkUser($args, 'Only authenticated users can create submissions.'); @@ -152,29 +160,69 @@ public function post($args) $submissionModel = MidasLoader::loadModel('Submission', $this->moduleName); + /** @var Tracker_ProducerModel $producerModel */ + $producerModel = MidasLoader::loadModel('Producer', $this->moduleName); + if (!isset($args['uuid'])) { /** @var UuidComponent $uuidComponent */ $uuidComponent = MidasLoader::loadComponent('UuidComponent'); $args['uuid'] = $uuidComponent->generate(); } + if (isset($args['extraUrls'])) { + $args['extra_urls'] = json_decode($args['extraUrls'], true); + } + + $args['build_results_url'] = isset($args['buildResultsUrl']) ? $args['buildResultsUrl'] : ''; + $args['branch'] = isset($args['branch']) ? $args['branch'] : ''; + $args['name'] = isset($args['name']) ? $args['name'] : ''; + $args['reproduction_command'] = isset($args['reproductionCommand']) ? $args['reproductionCommand'] : ''; + + $submitTime = strtotime($args['submitTime']); + if ($submitTime === false) { + throw new Exception('Invalid submitTime value: '.$args['submitTime'], -1); + } + $submitTime = date('Y-m-d H:i:s', $submitTime); + $args['submit_time'] = $submitTime; + $args['producer_revision'] = trim($args['producerRevision']); + /** @var Tracker_ProducerDao $producerDao */ + $producerDao = $producerModel->getByCommunityIdAndName( + $args['communityId'], + $args['producerDisplayName'] + ); + $args['producer_id'] = $producerDao->getKey(); + + // Remove params from the submission args for later insertion in param table + if (isset($args['params']) && !is_null($args['params'])) { + $params = $args['params']; + unset($args['params']); + } + /** @var Tracker_SubmissionDao $submissionDao */ $submissionDao = $submissionModel->initDao('Submission', - $args, - $this->moduleName); + $args, + $this->moduleName); // Catch violation of the unique constraint. try { $submissionModel->save($submissionDao); } catch (Zend_Db_Statement_Exception $e) { - throw new Exception('That uuid is already in use.', + throw new Exception('That uuid is already in use', MIDAS_INVALID_PARAMETER); } - $submissionId = $submissionDao->getSubmissionId(); - - /** @var Tracker_SubmissionDao $submissionDao */ - $submissionDao = $submissionModel->load($submissionId); + if (isset($params) && is_string($params)) { + $params = json_decode($params); + $paramModel = MidasLoader::loadModel('Param', $this->moduleName); + foreach ($params as $paramName => $paramValue) { + /** @var Tracker_ParamDao $paramDao */ + $paramDao = MidasLoader::newDao('ParamDao', $this->moduleName); + $paramDao->setSubmissionId($submissionDao->getKey()); + $paramDao->setParamName($paramName); + $paramDao->setParamValue($paramValue); + $paramModel->save($paramDao); + } + } return $this->_toArray($submissionDao); } @@ -185,8 +233,12 @@ public function post($args) * @path /tracker/submission/{id} * @http PUT * @param id - * @param uuid (Optional) * @param name (Optional) + * @param submitTime (Optional) + * @param branch (Optional) + * @param buildResultsUrl (Optional) + * @param extraUrls (Optional) + * @param reproductionCommand (Optional) * @return array * * @param array $args parameters @@ -218,6 +270,20 @@ public function put($args) ' does not exist.', MIDAS_NOT_FOUND); } + if (isset($args['submitTime'])) { + $submitTime = strtotime($args['submitTime']); + if ($submitTime === false) { + throw new Exception('Invalid submitTime value: '.$args['submitTime'], -1); + } + $submitTime = date('Y-m-d H:i:s', $submitTime); + $args['submitTime'] = $submitTime; + } + + // Disallow modification of the uuid. + if (isset($args['uuid'])) { + unset($args['uuid']); + } + /** @var Tracker_SubmissionDao $submissionDao */ $submissionDao = $submissionModel->initDao('Submission', $args, $this->moduleName); diff --git a/modules/tracker/database/mysql/2.0.0.sql b/modules/tracker/database/mysql/2.0.0.sql new file mode 100644 index 000000000..2dc965dd5 --- /dev/null +++ b/modules/tracker/database/mysql/2.0.0.sql @@ -0,0 +1,132 @@ +-- Midas Server. Copyright Kitware SAS. Licensed under the Apache License 2.0. + +-- MySQL database for the tracker module, version 2.0.0 + +CREATE TABLE IF NOT EXISTS `tracker_producer` ( + `producer_id` bigint(20) NOT NULL AUTO_INCREMENT, + `community_id` bigint(20) NOT NULL, + `repository` varchar(255) NOT NULL, + `executable_name` varchar(255) NOT NULL, + `display_name` varchar(255) NOT NULL, + `description` text NOT NULL, + `revision_url` text NOT NULL, + PRIMARY KEY (`producer_id`), + KEY (`community_id`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_scalar` ( + `scalar_id` bigint(20) NOT NULL AUTO_INCREMENT, + `trend_id` bigint(20) NOT NULL, + `value` double, + `submission_id` bigint(20) NOT NULL, + PRIMARY KEY (`scalar_id`), + KEY (`trend_id`), + KEY (`submission_id`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_submission` ( + `submission_id` bigint(20) NOT NULL AUTO_INCREMENT, + `producer_id` bigint(20) NOT NULL, + `name` varchar(255) NOT NULL DEFAULT '', + `uuid` varchar(255) NOT NULL DEFAULT '', + `submit_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `producer_revision` varchar(255), + `user_id` bigint(20) NOT NULL DEFAULT '-1', + `official` tinyint(4) NOT NULL DEFAULT '1', + `build_results_url` text NOT NULL, + `branch` varchar(255) NOT NULL DEFAULT '', + `extra_urls` text, + `reproduction_command` text, + PRIMARY KEY (`submission_id`), + UNIQUE KEY (`uuid`), + KEY (`user_id`), + KEY (`submit_time`), + KEY (`branch`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_submission2item` ( + `submission_id` bigint(20) NOT NULL, + `item_id` bigint(20) NOT NULL, + `label` varchar(255) NOT NULL, + `trendgroup_id` bigint(20) NOT NULL, + KEY (`submission_id`), + KEY (`item_id`), + KEY (`trendgroup_id`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_threshold_notification` ( + `threshold_id` bigint(20) NOT NULL AUTO_INCREMENT, + `trend_id` bigint(20) NOT NULL, + `value` double, + `comparison` varchar(2), + `action` varchar(80) NOT NULL, + `recipient_id` bigint(20) NOT NULL, + PRIMARY KEY (`threshold_id`), + KEY (`trend_id`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_trend` ( + `trend_id` bigint(20) NOT NULL AUTO_INCREMENT, + `trendgroup_id` bigint(20), + `metric_name` varchar(255) NOT NULL, + `display_name` varchar(255) NOT NULL, + `unit` varchar(255) NOT NULL, + `key_metric` tinyint(4) NOT NULL DEFAULT '0', + PRIMARY KEY (`trend_id`), + KEY (`trendgroup_id`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_trendgroup` ( + `trendgroup_id` bigint(20) NOT NULL AUTO_INCREMENT, + `producer_id` bigint(20) NOT NULL, + `config_item_id` bigint(20), + `test_dataset_id` bigint(20), + `truth_dataset_id` bigint(20), + PRIMARY KEY (`trendgroup_id`), + KEY (`producer_id`), + KEY (`config_item_id`), + KEY (`test_dataset_id`), + KEY (`truth_dataset_id`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_param` ( + `param_id` bigint(20) NOT NULL AUTO_INCREMENT, + `submission_id` bigint(20) NOT NULL, + `param_name` varchar(255) NOT NULL, + `param_type` enum('text', 'numeric') NOT NULL, + `text_value` text, + `numeric_value` double, + PRIMARY KEY (`param_id`), + KEY (`submission_id`), + KEY (`param_name`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_aggregate_metric` ( + `aggregate_metric_id` bigint(20) NOT NULL AUTO_INCREMENT, + `aggregate_metric_spec_id` bigint(20) NOT NULL, + `submission_id` bigint(20) NOT NULL, + `value` double, + PRIMARY KEY (`aggregate_metric_id`), + KEY (`aggregate_metric_spec_id`), + KEY (`submission_id`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_aggregate_metric_spec` ( + `aggregate_metric_spec_id` bigint(20) NOT NULL AUTO_INCREMENT, + `producer_id` bigint(20) NOT NULL, + `branch` varchar(255) NOT NULL DEFAULT '', + `name` varchar(255) NOT NULL DEFAULT '', + `description` varchar(255) NOT NULL DEFAULT '', + `spec` text NOT NULL DEFAULT '', + `value` double, + `comparison` varchar(2) NOT NULL DEFAULT '', + PRIMARY KEY (`aggregate_metric_spec_id`), + KEY (`producer_id`), + KEY (`branch`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_user2aggregate_metric_spec` ( + `user_id` bigint(20) NOT NULL, + `aggregate_metric_spec_id` bigint(20) NOT NULL, + PRIMARY KEY (`user_id`, `aggregate_metric_spec_id`) +) DEFAULT CHARSET=utf8; diff --git a/modules/tracker/database/mysql/2.0.1.sql b/modules/tracker/database/mysql/2.0.1.sql new file mode 100644 index 000000000..239034638 --- /dev/null +++ b/modules/tracker/database/mysql/2.0.1.sql @@ -0,0 +1,139 @@ +-- Midas Server. Copyright Kitware SAS. Licensed under the Apache License 2.0. + +-- MySQL database for the tracker module, version 2.0.1 + +CREATE TABLE IF NOT EXISTS `tracker_producer` ( + `producer_id` bigint(20) NOT NULL AUTO_INCREMENT, + `community_id` bigint(20) NOT NULL, + `repository` varchar(255) NOT NULL, + `executable_name` varchar(255) NOT NULL, + `display_name` varchar(255) NOT NULL, + `description` text NOT NULL, + `revision_url` text NOT NULL, + PRIMARY KEY (`producer_id`), + KEY (`community_id`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_scalar` ( + `scalar_id` bigint(20) NOT NULL AUTO_INCREMENT, + `trend_id` bigint(20) NOT NULL, + `value` double, + `submission_id` bigint(20) NOT NULL, + PRIMARY KEY (`scalar_id`), + KEY (`trend_id`), + KEY (`submission_id`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_submission` ( + `submission_id` bigint(20) NOT NULL AUTO_INCREMENT, + `producer_id` bigint(20) NOT NULL, + `name` varchar(255) NOT NULL DEFAULT '', + `uuid` varchar(255) NOT NULL DEFAULT '', + `submit_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `producer_revision` varchar(255), + `user_id` bigint(20) NOT NULL DEFAULT '-1', + `official` tinyint(4) NOT NULL DEFAULT '1', + `build_results_url` text NOT NULL, + `branch` varchar(255) NOT NULL DEFAULT '', + `extra_urls` text, + `reproduction_command` text, + PRIMARY KEY (`submission_id`), + UNIQUE KEY (`uuid`), + KEY (`user_id`), + KEY (`submit_time`), + KEY (`branch`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_submission2item` ( + `submission_id` bigint(20) NOT NULL, + `item_id` bigint(20) NOT NULL, + `label` varchar(255) NOT NULL, + `trendgroup_id` bigint(20) NOT NULL, + KEY (`submission_id`), + KEY (`item_id`), + KEY (`trendgroup_id`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_threshold_notification` ( + `threshold_id` bigint(20) NOT NULL AUTO_INCREMENT, + `trend_id` bigint(20) NOT NULL, + `value` double, + `comparison` varchar(2), + `action` varchar(80) NOT NULL, + `recipient_id` bigint(20) NOT NULL, + PRIMARY KEY (`threshold_id`), + KEY (`trend_id`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_trend` ( + `trend_id` bigint(20) NOT NULL AUTO_INCREMENT, + `trendgroup_id` bigint(20), + `metric_name` varchar(255) NOT NULL, + `display_name` varchar(255) NOT NULL, + `unit` varchar(255) NOT NULL, + `key_metric` tinyint(4) NOT NULL DEFAULT '0', + PRIMARY KEY (`trend_id`), + KEY (`trendgroup_id`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_trendgroup` ( + `trendgroup_id` bigint(20) NOT NULL AUTO_INCREMENT, + `producer_id` bigint(20) NOT NULL, + `config_item_id` bigint(20), + `test_dataset_id` bigint(20), + `truth_dataset_id` bigint(20), + PRIMARY KEY (`trendgroup_id`), + KEY (`producer_id`), + KEY (`config_item_id`), + KEY (`test_dataset_id`), + KEY (`truth_dataset_id`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_param` ( + `param_id` bigint(20) NOT NULL AUTO_INCREMENT, + `submission_id` bigint(20) NOT NULL, + `param_name` varchar(255) NOT NULL, + `param_type` enum('text', 'numeric') NOT NULL, + `text_value` text, + `numeric_value` double, + PRIMARY KEY (`param_id`), + KEY (`submission_id`), + KEY (`param_name`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_aggregate_metric` ( + `aggregate_metric_id` bigint(20) NOT NULL AUTO_INCREMENT, + `aggregate_metric_spec_id` bigint(20) NOT NULL, + `submission_id` bigint(20) NOT NULL, + `value` double, + PRIMARY KEY (`aggregate_metric_id`), + KEY (`aggregate_metric_spec_id`), + KEY (`submission_id`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_aggregate_metric_spec` ( + `aggregate_metric_spec_id` bigint(20) NOT NULL AUTO_INCREMENT, + `producer_id` bigint(20) NOT NULL, + `name` varchar(255) NOT NULL DEFAULT '', + `description` varchar(255) NOT NULL DEFAULT '', + `spec` text NOT NULL DEFAULT '', + PRIMARY KEY (`aggregate_metric_spec_id`), + KEY (`producer_id`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_aggregate_metric_notification` ( + `aggregate_metric_notification_id` bigint(20) NOT NULL AUTO_INCREMENT, + `aggregate_metric_spec_id` bigint(20) NOT NULL, + `branch` varchar(255) NOT NULL DEFAULT '', + `value` double, + `comparison` varchar(2) NOT NULL DEFAULT '', + PRIMARY KEY (`aggregate_metric_notification_id`), + KEY (`aggregate_metric_spec_id`), + KEY (`branch`) +) DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tracker_user2aggregate_metric_notification` ( + `user_id` bigint(20) NOT NULL, + `aggregate_metric_notification_id` bigint(20) NOT NULL, + PRIMARY KEY (`user_id`, `aggregate_metric_notification_id`) +) DEFAULT CHARSET=utf8; diff --git a/modules/tracker/database/mysql/create_submissions.sql b/modules/tracker/database/mysql/create_submissions.sql new file mode 100644 index 000000000..cd7c5afa4 --- /dev/null +++ b/modules/tracker/database/mysql/create_submissions.sql @@ -0,0 +1,23 @@ +CREATE PROCEDURE `create_submissions`() +BEGIN + DECLARE finished INTEGER DEFAULT 0; + DECLARE cur_id bigint(20) default -1; + DECLARE cur_time timestamp default NOW(); + + DECLARE curs CURSOR FOR SELECT scalar_id, submit_time FROM tracker_scalar + WHERE submission_id=-1 group by submit_time; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1; + + OPEN curs; + + get_scalars: LOOP + FETCH curs INTO cur_id, cur_time; + IF finished = 1 THEN + LEAVE get_scalars; + END IF; + + INSERT INTO tracker_submission (uuid, submit_time) VALUES (UUID(), cur_time); + UPDATE tracker_scalar set submission_id=LAST_INSERT_ID() where submit_time=cur_time; + END LOOP get_scalars; + CLOSE curs; +END diff --git a/modules/tracker/database/mysql/create_trendgroups.sql b/modules/tracker/database/mysql/create_trendgroups.sql new file mode 100644 index 000000000..59f822abe --- /dev/null +++ b/modules/tracker/database/mysql/create_trendgroups.sql @@ -0,0 +1,32 @@ +CREATE PROCEDURE `create_trendgroups`() + BEGIN + DECLARE finished INTEGER DEFAULT 0; + DECLARE cur_producer_id bigint(20) default -1; + DECLARE cur_config_item_id bigint(20) default NULL; + DECLARE cur_test_dataset_id bigint(20) default NULL; + DECLARE cur_truth_dataset_id bigint(20) default NULL; + + DECLARE curs CURSOR FOR SELECT producer_id, config_item_id, test_dataset_id, truth_dataset_id + FROM tracker_trend + WHERE trendgroup_id=-1 GROUP BY config_item_id, test_dataset_id, truth_dataset_id, producer_id; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1; + + OPEN curs; + + get_trends: LOOP + FETCH curs INTO cur_producer_id, cur_config_item_id, cur_test_dataset_id, cur_truth_dataset_id; + IF finished = 1 THEN + LEAVE get_trends; + END IF; + + INSERT INTO tracker_trendgroup (producer_id, config_item_id, test_dataset_id, truth_dataset_id) + VALUES (cur_producer_id, cur_config_item_id, cur_test_dataset_id, cur_truth_dataset_id); + UPDATE tracker_trend SET trendgroup_id=LAST_INSERT_ID() + WHERE + producer_id=cur_producer_id AND + (config_item_id=cur_config_item_id OR (config_item_id IS NULL AND cur_config_item_id IS NULL)) AND + (test_dataset_id=cur_test_dataset_id OR (test_dataset_id IS NULL AND cur_test_dataset_id IS NULL)) AND + (truth_dataset_id=cur_truth_dataset_id OR (truth_dataset_id IS NULL AND cur_truth_dataset_id IS NULL)); + END LOOP get_trends; + CLOSE curs; + END diff --git a/modules/tracker/database/mysql/migrate_items_to_submissions.sql b/modules/tracker/database/mysql/migrate_items_to_submissions.sql new file mode 100644 index 000000000..d17330702 --- /dev/null +++ b/modules/tracker/database/mysql/migrate_items_to_submissions.sql @@ -0,0 +1,31 @@ +CREATE PROCEDURE `migrate_items_to_submissions`() +BEGIN + + DECLARE finished INTEGER DEFAULT 0; + DECLARE cur_item_id bigint(20) default -1; + DECLARE cur_submission_id bigint(20) default -1; + DECLARE cur_label varchar(255) default ''; + DECLARE cur_trendgroup_id bigint(20) default -1; + + DECLARE curs CURSOR FOR + SELECT DISTINCT ti.item_id, ti.label, tu.submission_id, tt.trendgroup_id FROM + tracker_scalar AS ts, tracker_submission AS tu, tracker_scalar2item AS ti, tracker_trend as tt WHERE + ts.submission_id=tu.submission_id AND ts.scalar_id=ti.scalar_id AND ts.trend_id=tt.trend_id; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1; + + OPEN curs; + + get_items: LOOP + FETCH curs INTO cur_item_id, cur_label, cur_submission_id, cur_trendgroup_id; + IF finished = 1 THEN + LEAVE get_items; + END IF; + + INSERT INTO tracker_submission2item (submission_id, item_id, label, trendgroup_id) + VALUES (cur_submission_id, cur_item_id, cur_label, cur_trendgroup_id); + + END LOOP get_items; + + CLOSE curs; + +END diff --git a/modules/tracker/database/mysql/migrate_params.sql b/modules/tracker/database/mysql/migrate_params.sql new file mode 100644 index 000000000..632f423fd --- /dev/null +++ b/modules/tracker/database/mysql/migrate_params.sql @@ -0,0 +1,28 @@ +CREATE PROCEDURE `migrate_params`() +BEGIN + + DECLARE finished INTEGER DEFAULT 0; + DECLARE cur_id bigint(20) default -1; + DECLARE cur_name varchar(255) default ''; + DECLARE cur_type enum('text', 'numeric') default 'text'; + DECLARE cur_text_value text default ''; + DECLARE cur_numeric_value double default 0; + + DECLARE curs CURSOR FOR SELECT submission_id, param_name, param_type, text_value, numeric_value + FROM tracker_param, tracker_scalar WHERE tracker_param.scalar_id=tracker_scalar.scalar_id + GROUP BY submission_id, param_name; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1; + + OPEN curs; + + get_params: LOOP + FETCH curs INTO cur_id, cur_name, cur_type, cur_text_value, cur_numeric_value; + IF finished = 1 THEN + LEAVE get_params; + END IF; + INSERT INTO tracker_submissionparam (submission_id, param_name, param_type, text_value, numeric_value) + VALUES (cur_id, cur_name, cur_type, cur_text_value, cur_numeric_value); + END LOOP get_params; + + CLOSE curs; +END diff --git a/modules/tracker/database/mysql/scalar_to_submission.sql b/modules/tracker/database/mysql/scalar_to_submission.sql new file mode 100644 index 000000000..bd5e0d74d --- /dev/null +++ b/modules/tracker/database/mysql/scalar_to_submission.sql @@ -0,0 +1,39 @@ +CREATE PROCEDURE `scalar_to_submission`() +BEGIN + + DECLARE finished INTEGER DEFAULT 0; + DECLARE cur_id bigint(20) default -1; + DECLARE cur_producer_revision varchar(255) default ''; + DECLARE cur_user_id bigint(20) default -1; + DECLARE cur_official tinyint(4) default 1; + DECLARE cur_build_results_url text default ''; + DECLARE cur_branch varchar(255) default ''; + DECLARE cur_extra_urls text default ''; + DECLARE cur_reproduction_command text default ''; + + DECLARE curs CURSOR FOR + SELECT ts.submission_id, ts.producer_revision, ts.user_id, ts.official, + ts.build_results_url, ts.branch, ts.extra_urls, ts.reproduction_command + FROM tracker_scalar AS ts, tracker_submission AS tu WHERE ts.submission_id = tu.submission_id + GROUP BY tu.submission_id; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1; + + OPEN curs; + + get_scalars: LOOP + FETCH curs INTO cur_id, cur_producer_revision, cur_user_id, cur_official, + cur_build_results_url, cur_branch, cur_extra_urls, cur_reproduction_command; + IF finished = 1 THEN + LEAVE get_scalars; + END IF; + + UPDATE tracker_submission SET + producer_revision=cur_producer_revision, user_id=cur_user_id, official=cur_official, + build_results_url=cur_build_results_url, branch=cur_branch, extra_urls=cur_extra_urls, + reproduction_command=cur_reproduction_command WHERE submission_id=cur_id; + + END LOOP get_scalars; + + CLOSE curs; + +END diff --git a/modules/tracker/database/mysql/upgrade_to_2.0.0.sql b/modules/tracker/database/mysql/upgrade_to_2.0.0.sql new file mode 100644 index 000000000..b6e693c93 --- /dev/null +++ b/modules/tracker/database/mysql/upgrade_to_2.0.0.sql @@ -0,0 +1,121 @@ +-- Midas Server. Copyright Kitware SAS. Licensed under the Apache License 2.0. + +select 'Starting migration ', CURTIME() as ''; +CREATE TABLE IF NOT EXISTS `tracker_submission2item` ( + `submission_id` bigint(20) NOT NULL, + `item_id` bigint(20) NOT NULL, + `label` varchar(255) NOT NULL, + `trendgroup_id` bigint(20) NOT NULL, + KEY (`submission_id`), + KEY (`item_id`), + KEY (`trendgroup_id`) +) DEFAULT CHARSET=utf8; +select 'created table tracker_submission2item', CURTIME() as ''; + +CREATE TABLE IF NOT EXISTS `tracker_submissionparam` ( + `param_id` bigint(20) NOT NULL AUTO_INCREMENT, + `submission_id` bigint(20) NOT NULL, + `param_name` varchar(255) NOT NULL, + `param_type` enum('text', 'numeric') NOT NULL, + `text_value` text, + `numeric_value` double, + PRIMARY KEY (`param_id`), + KEY (`submission_id`), + KEY (`param_name`) +) DEFAULT CHARSET=utf8; +select 'created table tracker_submissionparam', CURTIME() as ''; + +CREATE TABLE IF NOT EXISTS `tracker_trendgroup` ( + `trendgroup_id` bigint(20) NOT NULL AUTO_INCREMENT, + `producer_id` bigint(20) NOT NULL, + `config_item_id` bigint(20), + `test_dataset_id` bigint(20), + `truth_dataset_id` bigint(20), + PRIMARY KEY (`trendgroup_id`), + KEY (`producer_id`), + KEY (`config_item_id`), + KEY (`test_dataset_id`), + KEY (`truth_dataset_id`) +) DEFAULT CHARSET=utf8; +select 'created table tracker_trendgroup', CURTIME() as ''; + + +DROP PROCEDURE IF EXISTS `create_submissions`; +select 'dropped create_submissions', CURTIME() as ''; +DROP PROCEDURE IF EXISTS `migrate_items_to_submissions`; +select 'dropped migrate_items_to_submissions', CURTIME() as ''; +DROP PROCEDURE IF EXISTS `migrate_params`; +select 'dropped migrate_params', CURTIME() as ''; +DROP PROCEDURE IF EXISTS `scalar_to_submission`; +select 'dropped scalar_to_submission', CURTIME() as ''; +DROP PROCEDURE IF EXISTS `create_trendgroups`; +select 'dropped create_trendgroups', CURTIME() as ''; + +DELIMITER '$$' +SOURCE create_submissions.sql +SOURCE migrate_items_to_submissions.sql +SOURCE migrate_params.sql +SOURCE scalar_to_submission.sql +SOURCE create_trendgroups.sql +DELIMITER ';' +select 'sourced stored procedures', CURTIME() as ''; + +ALTER TABLE tracker_submission ADD COLUMN `producer_revision` VARCHAR(255); +ALTER TABLE tracker_submission ADD COLUMN `user_id` bigint(20) NOT NULL DEFAULT '-1'; +ALTER TABLE tracker_submission ADD COLUMN `official` tinyint(4) NOT NULL DEFAULT '1'; +ALTER TABLE tracker_submission ADD COLUMN `build_results_url` text NOT NULL; +ALTER TABLE tracker_submission ADD COLUMN `branch` varchar(255) NOT NULL DEFAULT ''; +ALTER TABLE tracker_submission ADD COLUMN `extra_urls` text; +ALTER TABLE tracker_submission ADD COLUMN `reproduction_command` text; + +ALTER TABLE tracker_submission ADD KEY (`user_id`); +ALTER TABLE tracker_submission ADD KEY(`submit_time`); +ALTER TABLE tracker_submission ADD KEY (`branch`); +select 'altered table tracker_submission', CURTIME() as ''; + +ALTER TABLE tracker_trend ADD COLUMN `trendgroup_id` bigint(20) NOT NULL DEFAULT '-1'; +ALTER TABLE tracker_trend ADD KEY (`trendgroup_id`); +select 'altered table tracker_trend', CURTIME() as ''; + +CALL create_submissions(); +select 'finished create_submissions', CURTIME() as ''; + +CALL migrate_params(); +select 'finished migrate_params', CURTIME() as ''; + +CALL create_trendgroups(); +select 'finished create_trendgroups', CURTIME() as ''; + +CALL migrate_items_to_submissions(); +select 'finished migrate_item_to_submissions', CURTIME() as ''; + +CALL scalar_to_submission(); +select 'finished scalar_to_submission', CURTIME() as ''; + +DROP TABLE IF EXISTS tracker_param; +select 'dropped table tracker_param', CURTIME() as ''; + +RENAME TABLE tracker_submissionparam TO tracker_param; +select 'renamed table to tracker_param', CURTIME() as ''; + +ALTER TABLE tracker_scalar CHANGE `submission_id` `submission_id` bigint(20) NOT NULL; +ALTER TABLE tracker_scalar + DROP COLUMN `producer_revision`, + DROP COLUMN `user_id`, + DROP COLUMN `official`, + DROP COLUMN `build_results_url`, + DROP COLUMN `branch`, + DROP COLUMN `extra_urls`, + DROP COLUMN `reproduction_command`, + DROP COLUMN `submit_time`; +select 'altered table tracker_scalar', CURTIME() as ''; + +DROP TABLE IF EXISTS `tracker_scalar2item`; +select 'dropped table tracker_scalar2item', CURTIME() as ''; + +ALTER TABLE tracker_trend + DROP COLUMN `producer_id`, + DROP COLUMN `config_item_id`, + DROP COLUMN `test_dataset_id`, + DROP COLUMN `truth_dataset_id`; +select 'altered table tracker_trend', CURTIME() as ''; diff --git a/modules/tracker/database/pgsql/1.0.0.sql b/modules/tracker/database/pgsql/1.0.0.sql deleted file mode 100644 index 751055d8a..000000000 --- a/modules/tracker/database/pgsql/1.0.0.sql +++ /dev/null @@ -1,61 +0,0 @@ --- Midas Server. Copyright Kitware SAS. Licensed under the Apache License 2.0. - --- PostgreSQL database for the tracker module, version 1.0.0 - -SET client_encoding = 'UTF8'; -SET default_with_oids = FALSE; - -CREATE TABLE IF NOT EXISTS "tracker_producer" ( - "producer_id" serial PRIMARY KEY, - "community_id" bigint NOT NULL, - "repository" character varying(255) NOT NULL, - "executable_name" character varying(255) NOT NULL, - "display_name" character varying(255) NOT NULL, - "description" text NOT NULL -); - -CREATE INDEX "tracker_producer_community_id" ON "tracker_producer" ("community_id"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar" ( - "scalar_id" serial PRIMARY KEY, - "trend_id" bigint NOT NULL, - value double precision, - "producer_revision" character varying(255), - "submit_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP -); - -CREATE INDEX "tracker_scalar_trend_id" ON "tracker_scalar" ("trend_id"); -CREATE INDEX "tracker_scalar_submit_time" ON "tracker_scalar" ("submit_time"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar2item" ( - "id" serial PRIMARY KEY, - "scalar_id" bigint NOT NULL, - "item_id" bigint NOT NULL, - "label" character varying(255) NOT NULL -); - -CREATE INDEX "tracker_scalar2item_scalar_id" ON "tracker_scalar2item" ("scalar_id"); - -CREATE TABLE IF NOT EXISTS "tracker_threshold_notification" ( - "threshold_id" serial PRIMARY KEY, - "trend_id" bigint NOT NULL, - "value" double precision, - "comparison" character varying(2), - "action" character varying(80) NOT NULL, - "recipient_id" bigint NOT NULL -); - -CREATE INDEX "tracker_threshold_notification_trend_id" ON "tracker_threshold_notification" ("trend_id"); - -CREATE TABLE IF NOT EXISTS "tracker_trend" ( - "trend_id" serial PRIMARY KEY, - "producer_id" bigint NOT NULL, - "metric_name" character varying(255) NOT NULL, - "display_name" character varying(255) NOT NULL, - "unit" character varying(255) NOT NULL, - "config_item_id" bigint, - "test_dataset_id" bigint, - "truth_dataset_id" bigint -); - -CREATE INDEX "tracker_trend_producer_id" ON "tracker_trend" ("producer_id"); diff --git a/modules/tracker/database/pgsql/1.2.0.sql b/modules/tracker/database/pgsql/1.2.0.sql deleted file mode 100644 index deeac3f8d..000000000 --- a/modules/tracker/database/pgsql/1.2.0.sql +++ /dev/null @@ -1,81 +0,0 @@ --- Midas Server. Copyright Kitware SAS. Licensed under the Apache License 2.0. - --- PostgreSQL database for the tracker module, version 1.2.0 - -SET client_encoding = 'UTF8'; -SET default_with_oids = FALSE; - -CREATE TABLE IF NOT EXISTS "tracker_producer" ( - "producer_id" serial PRIMARY KEY, - "community_id" bigint NOT NULL, - "repository" character varying(255) NOT NULL, - "executable_name" character varying(255) NOT NULL, - "display_name" character varying(255) NOT NULL, - "description" text NOT NULL, - "revision_url" text NOT NULL -); - -CREATE INDEX "tracker_producer_community_id" ON "tracker_producer" ("community_id"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar" ( - "scalar_id" serial PRIMARY KEY, - "trend_id" bigint NOT NULL, - "value" double precision, - "producer_revision" character varying(255), - "submit_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - "user_id" bigint NOT NULL DEFAULT -1::bigint, - "submission_id" bigint NOT NULL DEFAULT -1::bigint, - "official" smallint NOT NULL DEFAULT 1::smallint, - "build_results_url" text NOT NULL, - "branch" character varying(255) NOT NULL DEFAULT ''::character varying, - "params" text, - "extra_urls" text -); - -CREATE INDEX "tracker_scalar_trend_id" ON "tracker_scalar" ("trend_id"); -CREATE INDEX "tracker_scalar_submit_time" ON "tracker_scalar" ("submit_time"); -CREATE INDEX "tracker_scalar_idx_branch" ON "tracker_scalar" ("branch"); -CREATE INDEX "tracker_scalar_idx_user_id" ON "tracker_scalar" ("user_id"); - -CREATE TABLE IF NOT EXISTS "tracker_submission" ( - "submission_id" serial PRIMARY KEY, - "producer_id" bigint, - "name" character varying(255) NOT NULL DEFAULT ''::character varying, - "uuid" character varying(255) NOT NULL DEFAULT ''::character varying, - "submit_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP -); -CREATE UNIQUE INDEX "tracker_submission_uuid" ON "tracker_submission" ("uuid"); -CREATE INDEX "tracker_submission_submit_time" ON "tracker_submission" ("submit_time"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar2item" ( - "id" serial PRIMARY KEY, - "scalar_id" bigint NOT NULL, - "item_id" bigint NOT NULL, - "label" character varying(255) NOT NULL -); - -CREATE INDEX "tracker_scalar2item_scalar_id" ON "tracker_scalar2item" ("scalar_id"); - -CREATE TABLE IF NOT EXISTS "tracker_threshold_notification" ( - "threshold_id" serial PRIMARY KEY, - "trend_id" bigint NOT NULL, - "value" double precision, - "comparison" character varying(2), - "action" character varying(80) NOT NULL, - "recipient_id" bigint NOT NULL -); - -CREATE INDEX "tracker_threshold_notification_trend_id" ON "tracker_threshold_notification" ("trend_id"); - -CREATE TABLE IF NOT EXISTS "tracker_trend" ( - "trend_id" serial PRIMARY KEY, - "producer_id" bigint NOT NULL, - "metric_name" character varying(255) NOT NULL, - "display_name" character varying(255) NOT NULL, - "unit" character varying(255) NOT NULL, - "config_item_id" bigint, - "test_dataset_id" bigint, - "truth_dataset_id" bigint -); - -CREATE INDEX "tracker_trend_producer_id" ON "tracker_trend" ("producer_id"); diff --git a/modules/tracker/database/pgsql/1.2.1.sql b/modules/tracker/database/pgsql/1.2.1.sql deleted file mode 100644 index 18e09966d..000000000 --- a/modules/tracker/database/pgsql/1.2.1.sql +++ /dev/null @@ -1,82 +0,0 @@ --- Midas Server. Copyright Kitware SAS. Licensed under the Apache License 2.0. - --- PostgreSQL database for the tracker module, version 1.2.1 - -SET client_encoding = 'UTF8'; -SET default_with_oids = FALSE; - -CREATE TABLE IF NOT EXISTS "tracker_producer" ( - "producer_id" serial PRIMARY KEY, - "community_id" bigint NOT NULL, - "repository" character varying(255) NOT NULL, - "executable_name" character varying(255) NOT NULL, - "display_name" character varying(255) NOT NULL, - "description" text NOT NULL, - "revision_url" text NOT NULL -); - -CREATE INDEX "tracker_producer_community_id" ON "tracker_producer" ("community_id"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar" ( - "scalar_id" serial PRIMARY KEY, - "trend_id" bigint NOT NULL, - "value" double precision, - "producer_revision" character varying(255), - "submit_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - "user_id" bigint NOT NULL DEFAULT -1::bigint, - "submission_id" bigint NOT NULL DEFAULT -1::bigint, - "official" smallint NOT NULL DEFAULT 1::smallint, - "build_results_url" text NOT NULL, - "branch" character varying(255) NOT NULL DEFAULT ''::character varying, - "params" text, - "extra_urls" text -); - -CREATE INDEX "tracker_scalar_trend_id" ON "tracker_scalar" ("trend_id"); -CREATE INDEX "tracker_scalar_submit_time" ON "tracker_scalar" ("submit_time"); -CREATE INDEX "tracker_scalar_idx_branch" ON "tracker_scalar" ("branch"); -CREATE INDEX "tracker_scalar_idx_user_id" ON "tracker_scalar" ("user_id"); - -CREATE TABLE IF NOT EXISTS "tracker_submission" ( - "submission_id" serial PRIMARY KEY, - "producer_id" bigint, - "name" character varying(255) NOT NULL DEFAULT ''::character varying, - "uuid" character varying(255) NOT NULL DEFAULT ''::character varying, - "submit_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP -); -CREATE UNIQUE INDEX "tracker_submission_uuid" ON "tracker_submission" ("uuid"); -CREATE INDEX "tracker_submission_submit_time" ON "tracker_submission" ("submit_time"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar2item" ( - "id" serial PRIMARY KEY, - "scalar_id" bigint NOT NULL, - "item_id" bigint NOT NULL, - "label" character varying(255) NOT NULL -); - -CREATE INDEX "tracker_scalar2item_scalar_id" ON "tracker_scalar2item" ("scalar_id"); - -CREATE TABLE IF NOT EXISTS "tracker_threshold_notification" ( - "threshold_id" serial PRIMARY KEY, - "trend_id" bigint NOT NULL, - "value" double precision, - "comparison" character varying(2), - "action" character varying(80) NOT NULL, - "recipient_id" bigint NOT NULL -); - -CREATE INDEX "tracker_threshold_notification_trend_id" ON "tracker_threshold_notification" ("trend_id"); - -CREATE TABLE IF NOT EXISTS "tracker_trend" ( - "trend_id" serial PRIMARY KEY, - "producer_id" bigint NOT NULL, - "metric_name" character varying(255) NOT NULL, - "display_name" character varying(255) NOT NULL, - "unit" character varying(255) NOT NULL, - "config_item_id" bigint, - "test_dataset_id" bigint, - "truth_dataset_id" bigint, - "key_metric" smallint NOT NULL DEFAULT 0::smallint -); - -CREATE INDEX "tracker_trend_producer_id" ON "tracker_trend" ("producer_id"); diff --git a/modules/tracker/database/pgsql/1.2.2.sql b/modules/tracker/database/pgsql/1.2.2.sql deleted file mode 100644 index 76d9dbe0c..000000000 --- a/modules/tracker/database/pgsql/1.2.2.sql +++ /dev/null @@ -1,92 +0,0 @@ --- Midas Server. Copyright Kitware SAS. Licensed under the Apache License 2.0. - --- PostgreSQL database for the tracker module, version 1.2.2 - -SET client_encoding = 'UTF8'; -SET default_with_oids = FALSE; - -CREATE TABLE IF NOT EXISTS "tracker_producer" ( - "producer_id" serial PRIMARY KEY, - "community_id" bigint NOT NULL, - "repository" character varying(255) NOT NULL, - "executable_name" character varying(255) NOT NULL, - "display_name" character varying(255) NOT NULL, - "description" text NOT NULL, - "revision_url" text NOT NULL -); - -CREATE INDEX "tracker_producer_community_id" ON "tracker_producer" ("community_id"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar" ( - "scalar_id" serial PRIMARY KEY, - "trend_id" bigint NOT NULL, - "value" double precision, - "producer_revision" character varying(255), - "submit_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - "user_id" bigint NOT NULL DEFAULT -1::bigint, - "submission_id" bigint NOT NULL DEFAULT -1::bigint, - "official" smallint NOT NULL DEFAULT 1::smallint, - "build_results_url" text NOT NULL, - "branch" character varying(255) NOT NULL DEFAULT ''::character varying, - "extra_urls" text -); - -CREATE INDEX "tracker_scalar_trend_id" ON "tracker_scalar" ("trend_id"); -CREATE INDEX "tracker_scalar_submit_time" ON "tracker_scalar" ("submit_time"); -CREATE INDEX "tracker_scalar_idx_branch" ON "tracker_scalar" ("branch"); -CREATE INDEX "tracker_scalar_idx_user_id" ON "tracker_scalar" ("user_id"); - -CREATE TABLE IF NOT EXISTS "tracker_submission" ( - "submission_id" serial PRIMARY KEY, - "producer_id" bigint, - "name" character varying(255) NOT NULL DEFAULT ''::character varying, - "uuid" character varying(255) NOT NULL DEFAULT ''::character varying, - "submit_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP -); -CREATE UNIQUE INDEX "tracker_submission_uuid" ON "tracker_submission" ("uuid"); -CREATE INDEX "tracker_submission_submit_time" ON "tracker_submission" ("submit_time"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar2item" ( - "id" serial PRIMARY KEY, - "scalar_id" bigint NOT NULL, - "item_id" bigint NOT NULL, - "label" character varying(255) NOT NULL -); - -CREATE INDEX "tracker_scalar2item_scalar_id" ON "tracker_scalar2item" ("scalar_id"); - -CREATE TABLE IF NOT EXISTS "tracker_threshold_notification" ( - "threshold_id" serial PRIMARY KEY, - "trend_id" bigint NOT NULL, - "value" double precision, - "comparison" character varying(2), - "action" character varying(80) NOT NULL, - "recipient_id" bigint NOT NULL -); - -CREATE INDEX "tracker_threshold_notification_trend_id" ON "tracker_threshold_notification" ("trend_id"); - -CREATE TABLE IF NOT EXISTS "tracker_trend" ( - "trend_id" serial PRIMARY KEY, - "producer_id" bigint NOT NULL, - "metric_name" character varying(255) NOT NULL, - "display_name" character varying(255) NOT NULL, - "unit" character varying(255) NOT NULL, - "config_item_id" bigint, - "test_dataset_id" bigint, - "truth_dataset_id" bigint, - "key_metric" smallint NOT NULL DEFAULT 0::smallint -); - -CREATE INDEX "tracker_trend_producer_id" ON "tracker_trend" ("producer_id"); - -CREATE TABLE IF NOT EXISTS "tracker_param" ( - "param_id" serial PRIMARY KEY, - "scalar_id" bigint NOT NULL, - "param_name" character varying(255) NOT NULL, - "param_type" text CHECK (param_type IN ('text', 'numeric')), - "text_value" text, - "numeric_value" double precision -); - -CREATE INDEX "tracker_param_param_name_idx" ON "tracker_param" ("param_name"); diff --git a/modules/tracker/database/pgsql/1.2.3.sql b/modules/tracker/database/pgsql/1.2.3.sql deleted file mode 100644 index ed02a8029..000000000 --- a/modules/tracker/database/pgsql/1.2.3.sql +++ /dev/null @@ -1,93 +0,0 @@ --- Midas Server. Copyright Kitware SAS. Licensed under the Apache License 2.0. - --- PostgreSQL database for the tracker module, version 1.2.3 - -SET client_encoding = 'UTF8'; -SET default_with_oids = FALSE; - -CREATE TABLE IF NOT EXISTS "tracker_producer" ( - "producer_id" serial PRIMARY KEY, - "community_id" bigint NOT NULL, - "repository" character varying(255) NOT NULL, - "executable_name" character varying(255) NOT NULL, - "display_name" character varying(255) NOT NULL, - "description" text NOT NULL, - "revision_url" text NOT NULL -); - -CREATE INDEX "tracker_producer_community_id" ON "tracker_producer" ("community_id"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar" ( - "scalar_id" serial PRIMARY KEY, - "trend_id" bigint NOT NULL, - "value" double precision, - "producer_revision" character varying(255), - "submit_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - "user_id" bigint NOT NULL DEFAULT -1::bigint, - "submission_id" bigint NOT NULL DEFAULT -1::bigint, - "official" smallint NOT NULL DEFAULT 1::smallint, - "build_results_url" text NOT NULL, - "branch" character varying(255) NOT NULL DEFAULT ''::character varying, - "extra_urls" text, - "reproduction_command" text -); - -CREATE INDEX "tracker_scalar_trend_id" ON "tracker_scalar" ("trend_id"); -CREATE INDEX "tracker_scalar_submit_time" ON "tracker_scalar" ("submit_time"); -CREATE INDEX "tracker_scalar_idx_branch" ON "tracker_scalar" ("branch"); -CREATE INDEX "tracker_scalar_idx_user_id" ON "tracker_scalar" ("user_id"); - -CREATE TABLE IF NOT EXISTS "tracker_submission" ( - "submission_id" serial PRIMARY KEY, - "producer_id" bigint, - "name" character varying(255) NOT NULL DEFAULT ''::character varying, - "uuid" character varying(255) NOT NULL DEFAULT ''::character varying, - "submit_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP -); -CREATE UNIQUE INDEX "tracker_submission_uuid" ON "tracker_submission" ("uuid"); -CREATE INDEX "tracker_submission_submit_time" ON "tracker_submission" ("submit_time"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar2item" ( - "id" serial PRIMARY KEY, - "scalar_id" bigint NOT NULL, - "item_id" bigint NOT NULL, - "label" character varying(255) NOT NULL -); - -CREATE INDEX "tracker_scalar2item_scalar_id" ON "tracker_scalar2item" ("scalar_id"); - -CREATE TABLE IF NOT EXISTS "tracker_threshold_notification" ( - "threshold_id" serial PRIMARY KEY, - "trend_id" bigint NOT NULL, - "value" double precision, - "comparison" character varying(2), - "action" character varying(80) NOT NULL, - "recipient_id" bigint NOT NULL -); - -CREATE INDEX "tracker_threshold_notification_trend_id" ON "tracker_threshold_notification" ("trend_id"); - -CREATE TABLE IF NOT EXISTS "tracker_trend" ( - "trend_id" serial PRIMARY KEY, - "producer_id" bigint NOT NULL, - "metric_name" character varying(255) NOT NULL, - "display_name" character varying(255) NOT NULL, - "unit" character varying(255) NOT NULL, - "config_item_id" bigint, - "test_dataset_id" bigint, - "truth_dataset_id" bigint, - "key_metric" smallint NOT NULL DEFAULT 0::smallint -); - -CREATE INDEX "tracker_trend_producer_id" ON "tracker_trend" ("producer_id"); - -CREATE TABLE IF NOT EXISTS "tracker_param" ( - "param_id" serial PRIMARY KEY, - "scalar_id" bigint NOT NULL, - "param_name" character varying(255) NOT NULL, - "param_type" text CHECK (param_type IN ('text', 'numeric')), - "text_value" text, - "numeric_value" double precision -); - -CREATE INDEX "tracker_param_param_name_idx" ON "tracker_param" ("param_name"); diff --git a/modules/tracker/database/pgsql/1.2.4.sql b/modules/tracker/database/pgsql/1.2.4.sql deleted file mode 100644 index 9f5d5cf15..000000000 --- a/modules/tracker/database/pgsql/1.2.4.sql +++ /dev/null @@ -1,124 +0,0 @@ --- Midas Server. Copyright Kitware SAS. Licensed under the Apache License 2.0. - --- PostgreSQL database for the tracker module, version 1.2.4 - -SET client_encoding = 'UTF8'; -SET default_with_oids = FALSE; - -CREATE TABLE IF NOT EXISTS "tracker_producer" ( - "producer_id" serial PRIMARY KEY, - "community_id" bigint NOT NULL, - "repository" character varying(255) NOT NULL, - "executable_name" character varying(255) NOT NULL, - "display_name" character varying(255) NOT NULL, - "description" text NOT NULL, - "revision_url" text NOT NULL -); - -CREATE INDEX "tracker_producer_community_id" ON "tracker_producer" ("community_id"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar" ( - "scalar_id" serial PRIMARY KEY, - "trend_id" bigint NOT NULL, - "value" double precision, - "producer_revision" character varying(255), - "submit_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - "user_id" bigint NOT NULL DEFAULT -1::bigint, - "submission_id" bigint NOT NULL DEFAULT -1::bigint, - "official" smallint NOT NULL DEFAULT 1::smallint, - "build_results_url" text NOT NULL, - "branch" character varying(255) NOT NULL DEFAULT ''::character varying, - "extra_urls" text, - "reproduction_command" text -); - -CREATE INDEX "tracker_scalar_trend_id" ON "tracker_scalar" ("trend_id"); -CREATE INDEX "tracker_scalar_submit_time" ON "tracker_scalar" ("submit_time"); -CREATE INDEX "tracker_scalar_idx_branch" ON "tracker_scalar" ("branch"); -CREATE INDEX "tracker_scalar_idx_user_id" ON "tracker_scalar" ("user_id"); - -CREATE TABLE IF NOT EXISTS "tracker_submission" ( - "submission_id" serial PRIMARY KEY, - "producer_id" bigint, - "name" character varying(255) NOT NULL DEFAULT ''::character varying, - "uuid" character varying(255) NOT NULL DEFAULT ''::character varying, - "submit_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP -); -CREATE UNIQUE INDEX "tracker_submission_uuid" ON "tracker_submission" ("uuid"); -CREATE INDEX "tracker_submission_submit_time" ON "tracker_submission" ("submit_time"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar2item" ( - "id" serial PRIMARY KEY, - "scalar_id" bigint NOT NULL, - "item_id" bigint NOT NULL, - "label" character varying(255) NOT NULL -); - -CREATE INDEX "tracker_scalar2item_scalar_id" ON "tracker_scalar2item" ("scalar_id"); - -CREATE TABLE IF NOT EXISTS "tracker_threshold_notification" ( - "threshold_id" serial PRIMARY KEY, - "trend_id" bigint NOT NULL, - "value" double precision, - "comparison" character varying(2), - "action" character varying(80) NOT NULL, - "recipient_id" bigint NOT NULL -); - -CREATE INDEX "tracker_threshold_notification_trend_id" ON "tracker_threshold_notification" ("trend_id"); - -CREATE TABLE IF NOT EXISTS "tracker_trend" ( - "trend_id" serial PRIMARY KEY, - "producer_id" bigint NOT NULL, - "metric_name" character varying(255) NOT NULL, - "display_name" character varying(255) NOT NULL, - "unit" character varying(255) NOT NULL, - "config_item_id" bigint, - "test_dataset_id" bigint, - "truth_dataset_id" bigint, - "key_metric" smallint NOT NULL DEFAULT 0::smallint -); - -CREATE INDEX "tracker_trend_producer_id" ON "tracker_trend" ("producer_id"); - -CREATE TABLE IF NOT EXISTS "tracker_param" ( - "param_id" serial PRIMARY KEY, - "scalar_id" bigint NOT NULL, - "param_name" character varying(255) NOT NULL, - "param_type" text CHECK (param_type IN ('text', 'numeric')), - "text_value" text, - "numeric_value" double precision -); - -CREATE INDEX "tracker_param_param_name_idx" ON "tracker_param" ("param_name"); - -CREATE TABLE IF NOT EXISTS "tracker_aggregate_metric" ( - "aggregate_metric_id" serial PRIMARY KEY, - "aggregate_metric_spec_id" bigint NOT NULL, - "submission_id" bigint NOT NULL, - "value" double precision -); - -CREATE INDEX "tracker_aggregate_metric_aggregate_metric_spec_id" ON "tracker_aggregate_metric" ("aggregate_metric_spec_id"); -CREATE INDEX "tracker_aggregate_metric_submission_id" ON "tracker_aggregate_metric" ("submission_id"); - -CREATE TABLE IF NOT EXISTS "tracker_aggregate_metric_spec" ( - "aggregate_metric_spec_id" serial PRIMARY KEY, - "producer_id" bigint NOT NULL, - "branch" character varying(255) NOT NULL, - "name" character varying(255) NOT NULL, - "description" character varying(255) NOT NULL, - "spec" text, - "value" double precision, - "comparison" character varying(2) NOT NULL -); - -CREATE INDEX "tracker_aggregate_metric_spec_producer_id" ON "tracker_aggregate_metric_spec" ("producer_id"); -CREATE INDEX "tracker_aggregate_metric_spec_branch" ON "tracker_aggregate_metric_spec" ("branch"); - -CREATE TABLE IF NOT EXISTS "tracker_user2aggregate_metric_spec" ( - "id" serial PRIMARY KEY, - "user_id" bigint NOT NULL, - "aggregate_metric_spec_id" bigint NOT NULL, - UNIQUE ("user_id", "aggregate_metric_spec_id") -); diff --git a/modules/tracker/database/sqlite/1.2.0.sql b/modules/tracker/database/sqlite/1.2.0.sql deleted file mode 100644 index 9b4f0807b..000000000 --- a/modules/tracker/database/sqlite/1.2.0.sql +++ /dev/null @@ -1,80 +0,0 @@ --- Midas Server. Copyright Kitware SAS. Licensed under the Apache License 2.0. - --- SQLite database for the tracker module, version 1.2.0 - -CREATE TABLE IF NOT EXISTS "tracker_producer" ( - "producer_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "community_id" INTEGER NOT NULL, - "repository" TEXT NOT NULL, - "executable_name" TEXT NOT NULL, - "display_name" TEXT NOT NULL, - "description" TEXT NOT NULL, - "revision_url" TEXT NOT NULL -); - -CREATE INDEX IF NOT EXISTS "tracker_producer_community_id_idx" ON "tracker_producer" ("community_id"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar" ( - "scalar_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "trend_id" INTEGER NOT NULL, - "value" REAL, - "producer_revision" TEXT, - "submit_time" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, - "user_id" INTEGER NOT NULL DEFAULT -1, - "submission_id" INTEGER NOT NULL DEFAULT -1, - "official" INTEGER NOT NULL DEFAULT 1, - "build_results_url" TEXT NOT NULL, - "branch" TEXT NOT NULL DEFAULT '', - "params" TEXT, - "extra_urls" TEXT -); - -CREATE INDEX IF NOT EXISTS "tracker_scalar_trend_id_idx" ON "tracker_scalar" ("trend_id"); -CREATE INDEX IF NOT EXISTS "tracker_scalar_submit_time_idx" ON "tracker_scalar" ("submit_time"); -CREATE INDEX IF NOT EXISTS "tracker_scalar_branch_idx" ON "tracker_scalar" ("branch"); -CREATE INDEX IF NOT EXISTS "tracker_scalar_user_id_idx" ON "tracker_scalar" ("user_id"); - - -CREATE TABLE IF NOT EXISTS "tracker_submission" ( - "submission_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "producer_id" INTEGER NOT NULL, - "name" TEXT NOT NULL DEFAULT '', - "uuid" TEXT NOT NULL DEFAULT '', - "submit_time" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP -); -CREATE UNIQUE INDEX IF NOT EXISTS "tracker_submission_uuid_idx" ON "tracker_submission" ("uuid"); -CREATE INDEX IF NOT EXISTS "tracker_submission_submit_time_idx" ON "tracker_submission" ("submit_time"); - - -CREATE TABLE IF NOT EXISTS "tracker_scalar2item" ( - "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "scalar_id" INTEGER NOT NULL, - "item_id" INTEGER NOT NULL, - "label" TEXT NOT NULL -); - -CREATE INDEX IF NOT EXISTS "tracker_scalar2item_scalar_id_idx" ON "tracker_scalar2item" ("scalar_id"); - -CREATE TABLE IF NOT EXISTS "tracker_threshold_notification" ( - "threshold_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "trend_id" INTEGER NOT NULL, - "value" REAL, - "comparison" TEXT, - "action" TEXT NOT NULL, - "recipient_id" INTEGER NOT NULL -); - -CREATE INDEX IF NOT EXISTS "tracker_threshold_notification_trend_id_idx" ON "tracker_threshold_notification" ("trend_id"); - -CREATE TABLE IF NOT EXISTS "tracker_trend" ( - "trend_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "producer_id" INTEGER NOT NULL, - "metric_name" TEXT NOT NULL, - "display_name" TEXT NOT NULL, - "unit" TEXT NOT NULL, - "config_item_id" INTEGER, - "test_dataset_id" INTEGER, - "truth_dataset_id" INTEGER -); - -CREATE INDEX IF NOT EXISTS "tracker_trend_producer_id_idx" ON "tracker_trend" ("producer_id"); diff --git a/modules/tracker/database/sqlite/1.2.1.sql b/modules/tracker/database/sqlite/1.2.1.sql deleted file mode 100644 index bc77b7a00..000000000 --- a/modules/tracker/database/sqlite/1.2.1.sql +++ /dev/null @@ -1,81 +0,0 @@ --- Midas Server. Copyright Kitware SAS. Licensed under the Apache License 2.0. - --- SQLite database for the tracker module, version 1.2.1 - -CREATE TABLE IF NOT EXISTS "tracker_producer" ( - "producer_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "community_id" INTEGER NOT NULL, - "repository" TEXT NOT NULL, - "executable_name" TEXT NOT NULL, - "display_name" TEXT NOT NULL, - "description" TEXT NOT NULL, - "revision_url" TEXT NOT NULL -); - -CREATE INDEX IF NOT EXISTS "tracker_producer_community_id_idx" ON "tracker_producer" ("community_id"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar" ( - "scalar_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "trend_id" INTEGER NOT NULL, - "value" REAL, - "producer_revision" TEXT, - "submit_time" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, - "user_id" INTEGER NOT NULL DEFAULT -1, - "submission_id" INTEGER NOT NULL DEFAULT -1, - "official" INTEGER NOT NULL DEFAULT 1, - "build_results_url" TEXT NOT NULL, - "branch" TEXT NOT NULL DEFAULT '', - "params" TEXT, - "extra_urls" TEXT -); - -CREATE INDEX IF NOT EXISTS "tracker_scalar_trend_id_idx" ON "tracker_scalar" ("trend_id"); -CREATE INDEX IF NOT EXISTS "tracker_scalar_submit_time_idx" ON "tracker_scalar" ("submit_time"); -CREATE INDEX IF NOT EXISTS "tracker_scalar_branch_idx" ON "tracker_scalar" ("branch"); -CREATE INDEX IF NOT EXISTS "tracker_scalar_user_id_idx" ON "tracker_scalar" ("user_id"); - - -CREATE TABLE IF NOT EXISTS "tracker_submission" ( - "submission_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "producer_id" INTEGER NOT NULL, - "name" TEXT NOT NULL DEFAULT '', - "uuid" TEXT NOT NULL DEFAULT '', - "submit_time" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP -); -CREATE UNIQUE INDEX IF NOT EXISTS "tracker_submission_uuid_idx" ON "tracker_submission" ("uuid"); -CREATE INDEX IF NOT EXISTS "tracker_submission_submit_time_idx" ON "tracker_submission" ("submit_time"); - - -CREATE TABLE IF NOT EXISTS "tracker_scalar2item" ( - "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "scalar_id" INTEGER NOT NULL, - "item_id" INTEGER NOT NULL, - "label" TEXT NOT NULL -); - -CREATE INDEX IF NOT EXISTS "tracker_scalar2item_scalar_id_idx" ON "tracker_scalar2item" ("scalar_id"); - -CREATE TABLE IF NOT EXISTS "tracker_threshold_notification" ( - "threshold_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "trend_id" INTEGER NOT NULL, - "value" REAL, - "comparison" TEXT, - "action" TEXT NOT NULL, - "recipient_id" INTEGER NOT NULL -); - -CREATE INDEX IF NOT EXISTS "tracker_threshold_notification_trend_id_idx" ON "tracker_threshold_notification" ("trend_id"); - -CREATE TABLE IF NOT EXISTS "tracker_trend" ( - "trend_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "producer_id" INTEGER NOT NULL, - "metric_name" TEXT NOT NULL, - "display_name" TEXT NOT NULL, - "unit" TEXT NOT NULL, - "config_item_id" INTEGER, - "test_dataset_id" INTEGER, - "truth_dataset_id" INTEGER, - "key_metric" INTEGER NOT NULL DEFAULT 0 -); - -CREATE INDEX IF NOT EXISTS "tracker_trend_producer_id_idx" ON "tracker_trend" ("producer_id"); diff --git a/modules/tracker/database/sqlite/1.2.2.sql b/modules/tracker/database/sqlite/1.2.2.sql deleted file mode 100644 index 1857833ae..000000000 --- a/modules/tracker/database/sqlite/1.2.2.sql +++ /dev/null @@ -1,90 +0,0 @@ --- Midas Server. Copyright Kitware SAS. Licensed under the Apache License 2.0. - --- SQLite database for the tracker module, version 1.2.2 - -CREATE TABLE IF NOT EXISTS "tracker_producer" ( - "producer_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "community_id" INTEGER NOT NULL, - "repository" TEXT NOT NULL, - "executable_name" TEXT NOT NULL, - "display_name" TEXT NOT NULL, - "description" TEXT NOT NULL, - "revision_url" TEXT NOT NULL -); - -CREATE INDEX IF NOT EXISTS "tracker_producer_community_id_idx" ON "tracker_producer" ("community_id"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar" ( - "scalar_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "trend_id" INTEGER NOT NULL, - "value" REAL, - "producer_revision" TEXT, - "submit_time" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, - "user_id" INTEGER NOT NULL DEFAULT -1, - "submission_id" INTEGER NOT NULL DEFAULT -1, - "official" INTEGER NOT NULL DEFAULT 1, - "build_results_url" TEXT NOT NULL, - "branch" TEXT NOT NULL DEFAULT '', - "extra_urls" TEXT -); - -CREATE INDEX IF NOT EXISTS "tracker_scalar_trend_id_idx" ON "tracker_scalar" ("trend_id"); -CREATE INDEX IF NOT EXISTS "tracker_scalar_submit_time_idx" ON "tracker_scalar" ("submit_time"); -CREATE INDEX IF NOT EXISTS "tracker_scalar_branch_idx" ON "tracker_scalar" ("branch"); -CREATE INDEX IF NOT EXISTS "tracker_scalar_user_id_idx" ON "tracker_scalar" ("user_id"); - - -CREATE TABLE IF NOT EXISTS "tracker_submission" ( - "submission_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "producer_id" INTEGER NOT NULL, - "name" TEXT NOT NULL DEFAULT '', - "uuid" TEXT NOT NULL DEFAULT '', - "submit_time" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP -); -CREATE UNIQUE INDEX IF NOT EXISTS "tracker_submission_uuid_idx" ON "tracker_submission" ("uuid"); -CREATE INDEX IF NOT EXISTS "tracker_submission_submit_time_idx" ON "tracker_submission" ("submit_time"); - - -CREATE TABLE IF NOT EXISTS "tracker_scalar2item" ( - "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "scalar_id" INTEGER NOT NULL, - "item_id" INTEGER NOT NULL, - "label" TEXT NOT NULL -); - -CREATE INDEX IF NOT EXISTS "tracker_scalar2item_scalar_id_idx" ON "tracker_scalar2item" ("scalar_id"); - -CREATE TABLE IF NOT EXISTS "tracker_threshold_notification" ( - "threshold_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "trend_id" INTEGER NOT NULL, - "value" REAL, - "comparison" TEXT, - "action" TEXT NOT NULL, - "recipient_id" INTEGER NOT NULL -); - -CREATE INDEX IF NOT EXISTS "tracker_threshold_notification_trend_id_idx" ON "tracker_threshold_notification" ("trend_id"); - -CREATE TABLE IF NOT EXISTS "tracker_trend" ( - "trend_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "producer_id" INTEGER NOT NULL, - "metric_name" TEXT NOT NULL, - "display_name" TEXT NOT NULL, - "unit" TEXT NOT NULL, - "config_item_id" INTEGER, - "test_dataset_id" INTEGER, - "truth_dataset_id" INTEGER, - "key_metric" INTEGER NOT NULL DEFAULT 0 -); - -CREATE INDEX IF NOT EXISTS "tracker_trend_producer_id_idx" ON "tracker_trend" ("producer_id"); - -CREATE TABLE IF NOT EXISTS "tracker_param" ( - "param_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "scalar_id" INTEGER NOT NULL, - "param_name" TEXT NOT NULL, - "param_type" TEXT CHECK( param_type in ('text', 'numeric') ) NOT NULL, - "text_value" text, - "numeric_value" REAL -); -CREATE INDEX IF NOT EXISTS "tracker_param_param_name" ON "tracker_param" ("param_name"); diff --git a/modules/tracker/database/sqlite/1.2.3.sql b/modules/tracker/database/sqlite/1.2.3.sql deleted file mode 100644 index cfdfc1e2f..000000000 --- a/modules/tracker/database/sqlite/1.2.3.sql +++ /dev/null @@ -1,91 +0,0 @@ --- Midas Server. Copyright Kitware SAS. Licensed under the Apache License 2.0. - --- SQLite database for the tracker module, version 1.2.3 - -CREATE TABLE IF NOT EXISTS "tracker_producer" ( - "producer_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "community_id" INTEGER NOT NULL, - "repository" TEXT NOT NULL, - "executable_name" TEXT NOT NULL, - "display_name" TEXT NOT NULL, - "description" TEXT NOT NULL, - "revision_url" TEXT NOT NULL -); - -CREATE INDEX IF NOT EXISTS "tracker_producer_community_id_idx" ON "tracker_producer" ("community_id"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar" ( - "scalar_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "trend_id" INTEGER NOT NULL, - "value" REAL, - "producer_revision" TEXT, - "submit_time" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, - "user_id" INTEGER NOT NULL DEFAULT -1, - "submission_id" INTEGER NOT NULL DEFAULT -1, - "official" INTEGER NOT NULL DEFAULT 1, - "build_results_url" TEXT NOT NULL, - "branch" TEXT NOT NULL DEFAULT '', - "extra_urls" TEXT, - "reproduction_command" TEXT -); - -CREATE INDEX IF NOT EXISTS "tracker_scalar_trend_id_idx" ON "tracker_scalar" ("trend_id"); -CREATE INDEX IF NOT EXISTS "tracker_scalar_submit_time_idx" ON "tracker_scalar" ("submit_time"); -CREATE INDEX IF NOT EXISTS "tracker_scalar_branch_idx" ON "tracker_scalar" ("branch"); -CREATE INDEX IF NOT EXISTS "tracker_scalar_user_id_idx" ON "tracker_scalar" ("user_id"); - - -CREATE TABLE IF NOT EXISTS "tracker_submission" ( - "submission_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "producer_id" INTEGER NOT NULL, - "name" TEXT NOT NULL DEFAULT '', - "uuid" TEXT NOT NULL DEFAULT '', - "submit_time" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP -); -CREATE UNIQUE INDEX IF NOT EXISTS "tracker_submission_uuid_idx" ON "tracker_submission" ("uuid"); -CREATE INDEX IF NOT EXISTS "tracker_submission_submit_time_idx" ON "tracker_submission" ("submit_time"); - - -CREATE TABLE IF NOT EXISTS "tracker_scalar2item" ( - "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "scalar_id" INTEGER NOT NULL, - "item_id" INTEGER NOT NULL, - "label" TEXT NOT NULL -); - -CREATE INDEX IF NOT EXISTS "tracker_scalar2item_scalar_id_idx" ON "tracker_scalar2item" ("scalar_id"); - -CREATE TABLE IF NOT EXISTS "tracker_threshold_notification" ( - "threshold_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "trend_id" INTEGER NOT NULL, - "value" REAL, - "comparison" TEXT, - "action" TEXT NOT NULL, - "recipient_id" INTEGER NOT NULL -); - -CREATE INDEX IF NOT EXISTS "tracker_threshold_notification_trend_id_idx" ON "tracker_threshold_notification" ("trend_id"); - -CREATE TABLE IF NOT EXISTS "tracker_trend" ( - "trend_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "producer_id" INTEGER NOT NULL, - "metric_name" TEXT NOT NULL, - "display_name" TEXT NOT NULL, - "unit" TEXT NOT NULL, - "config_item_id" INTEGER, - "test_dataset_id" INTEGER, - "truth_dataset_id" INTEGER, - "key_metric" INTEGER NOT NULL DEFAULT 0 -); - -CREATE INDEX IF NOT EXISTS "tracker_trend_producer_id_idx" ON "tracker_trend" ("producer_id"); - -CREATE TABLE IF NOT EXISTS "tracker_param" ( - "param_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "scalar_id" INTEGER NOT NULL, - "param_name" TEXT NOT NULL, - "param_type" TEXT CHECK( param_type in ('text', 'numeric') ) NOT NULL, - "text_value" text, - "numeric_value" REAL -); -CREATE INDEX IF NOT EXISTS "tracker_param_param_name" ON "tracker_param" ("param_name"); diff --git a/modules/tracker/database/sqlite/1.2.4.sql b/modules/tracker/database/sqlite/1.2.4.sql deleted file mode 100644 index fdec8a76e..000000000 --- a/modules/tracker/database/sqlite/1.2.4.sql +++ /dev/null @@ -1,122 +0,0 @@ --- Midas Server. Copyright Kitware SAS. Licensed under the Apache License 2.0. - --- SQLite database for the tracker module, version 1.2.4 - -CREATE TABLE IF NOT EXISTS "tracker_producer" ( - "producer_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "community_id" INTEGER NOT NULL, - "repository" TEXT NOT NULL, - "executable_name" TEXT NOT NULL, - "display_name" TEXT NOT NULL, - "description" TEXT NOT NULL, - "revision_url" TEXT NOT NULL -); - -CREATE INDEX IF NOT EXISTS "tracker_producer_community_id_idx" ON "tracker_producer" ("community_id"); - -CREATE TABLE IF NOT EXISTS "tracker_scalar" ( - "scalar_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "trend_id" INTEGER NOT NULL, - "value" REAL, - "producer_revision" TEXT, - "submit_time" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, - "user_id" INTEGER NOT NULL DEFAULT -1, - "submission_id" INTEGER NOT NULL DEFAULT -1, - "official" INTEGER NOT NULL DEFAULT 1, - "build_results_url" TEXT NOT NULL, - "branch" TEXT NOT NULL DEFAULT '', - "extra_urls" TEXT, - "reproduction_command" TEXT -); - -CREATE INDEX IF NOT EXISTS "tracker_scalar_trend_id_idx" ON "tracker_scalar" ("trend_id"); -CREATE INDEX IF NOT EXISTS "tracker_scalar_submit_time_idx" ON "tracker_scalar" ("submit_time"); -CREATE INDEX IF NOT EXISTS "tracker_scalar_branch_idx" ON "tracker_scalar" ("branch"); -CREATE INDEX IF NOT EXISTS "tracker_scalar_user_id_idx" ON "tracker_scalar" ("user_id"); - - -CREATE TABLE IF NOT EXISTS "tracker_submission" ( - "submission_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "producer_id" INTEGER NOT NULL, - "name" TEXT NOT NULL DEFAULT '', - "uuid" TEXT NOT NULL DEFAULT '', - "submit_time" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP -); -CREATE UNIQUE INDEX IF NOT EXISTS "tracker_submission_uuid_idx" ON "tracker_submission" ("uuid"); -CREATE INDEX IF NOT EXISTS "tracker_submission_submit_time_idx" ON "tracker_submission" ("submit_time"); - - -CREATE TABLE IF NOT EXISTS "tracker_scalar2item" ( - "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "scalar_id" INTEGER NOT NULL, - "item_id" INTEGER NOT NULL, - "label" TEXT NOT NULL -); - -CREATE INDEX IF NOT EXISTS "tracker_scalar2item_scalar_id_idx" ON "tracker_scalar2item" ("scalar_id"); - -CREATE TABLE IF NOT EXISTS "tracker_threshold_notification" ( - "threshold_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "trend_id" INTEGER NOT NULL, - "value" REAL, - "comparison" TEXT, - "action" TEXT NOT NULL, - "recipient_id" INTEGER NOT NULL -); - -CREATE INDEX IF NOT EXISTS "tracker_threshold_notification_trend_id_idx" ON "tracker_threshold_notification" ("trend_id"); - -CREATE TABLE IF NOT EXISTS "tracker_trend" ( - "trend_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "producer_id" INTEGER NOT NULL, - "metric_name" TEXT NOT NULL, - "display_name" TEXT NOT NULL, - "unit" TEXT NOT NULL, - "config_item_id" INTEGER, - "test_dataset_id" INTEGER, - "truth_dataset_id" INTEGER, - "key_metric" INTEGER NOT NULL DEFAULT 0 -); - -CREATE INDEX IF NOT EXISTS "tracker_trend_producer_id_idx" ON "tracker_trend" ("producer_id"); - -CREATE TABLE IF NOT EXISTS "tracker_param" ( - "param_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "scalar_id" INTEGER NOT NULL, - "param_name" TEXT NOT NULL, - "param_type" TEXT CHECK( param_type in ('text', 'numeric') ) NOT NULL, - "text_value" text, - "numeric_value" REAL -); -CREATE INDEX IF NOT EXISTS "tracker_param_param_name" ON "tracker_param" ("param_name"); - -CREATE TABLE IF NOT EXISTS "tracker_aggregate_metric" ( - "aggregate_metric_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "aggregate_metric_spec_id" INTEGER NOT NULL, - "submission_id" INTEGER NOT NULL, - "value" REAL -); - -CREATE INDEX IF NOT EXISTS "tracker_aggregate_metric_aggregate_metric_spec_id" ON "tracker_aggregate_metric" ("aggregate_metric_spec_id"); -CREATE INDEX IF NOT EXISTS "tracker_aggregate_metric_submission_id" ON "tracker_aggregate_metric" ("submission_id"); - -CREATE TABLE IF NOT EXISTS "tracker_aggregate_metric_spec" ( - "aggregate_metric_spec_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "producer_id" INTEGER NOT NULL, - "branch" TEXT NOT NULL, - "name" TEXT NOT NULL, - "description" TEXT NOT NULL, - "spec" TEXT NOT NULL, - "value" REAL, - "comparison" TEXT NOT NULL -); - -CREATE INDEX IF NOT EXISTS "tracker_aggregate_metric_spec_producer_id" ON "tracker_aggregate_metric_spec" ("producer_id"); -CREATE INDEX IF NOT EXISTS "tracker_aggregate_metric_spec_branch" ON "tracker_aggregate_metric_spec" ("branch"); - -CREATE TABLE IF NOT EXISTS "tracker_user2aggregate_metric_spec" ( - "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - "user_id" INTEGER NOT NULL, - "aggregate_metric_spec_id" INTEGER NOT NULL, - UNIQUE ("user_id", "aggregate_metric_spec_id") -); diff --git a/modules/tracker/database/upgrade/1.0.1.php b/modules/tracker/database/upgrade/1.0.1.php index 42eb1eede..9e5ef2ae8 100644 --- a/modules/tracker/database/upgrade/1.0.1.php +++ b/modules/tracker/database/upgrade/1.0.1.php @@ -33,12 +33,4 @@ public function mysql() $this->db->query("ALTER TABLE `tracker_scalar` ADD COLUMN `official` tinyint(4) NOT NULL DEFAULT '1';"); $this->db->query('ALTER TABLE `tracker_scalar` ADD KEY (`user_id`);'); } - - /** Upgrade a PostgreSQL database. */ - public function pgsql() - { - $this->db->query('ALTER TABLE tracker_scalar ADD COLUMN user_id bigint NOT NULL DEFAULT -1::bigint;'); - $this->db->query('ALTER TABLE tracker_scalar ADD COLUMN official smallint NOT NULL DEFAULT 1::smallint;'); - $this->db->query('CREATE INDEX tracker_scalar_idx_user_id ON tracker_scalar (user_id);'); - } } diff --git a/modules/tracker/database/upgrade/1.0.2.php b/modules/tracker/database/upgrade/1.0.2.php index c6a66fe22..8fb82f783 100644 --- a/modules/tracker/database/upgrade/1.0.2.php +++ b/modules/tracker/database/upgrade/1.0.2.php @@ -29,10 +29,4 @@ public function mysql() { $this->db->query('ALTER TABLE `tracker_producer` ADD COLUMN `revision_url` text NOT NULL;'); } - - /** Upgrade a PostgreSQL database. */ - public function pgsql() - { - $this->db->query("ALTER TABLE tracker_producer ADD COLUMN revision_url text NOT NULL DEFAULT '';"); - } } diff --git a/modules/tracker/database/upgrade/1.0.3.php b/modules/tracker/database/upgrade/1.0.3.php index a38e939e3..5e2c61f27 100644 --- a/modules/tracker/database/upgrade/1.0.3.php +++ b/modules/tracker/database/upgrade/1.0.3.php @@ -26,10 +26,4 @@ public function mysql() { $this->db->query('ALTER TABLE `tracker_scalar` ADD COLUMN `build_results_url` text NOT NULL;'); } - - /** Upgrade a PostgreSQL database. */ - public function pgsql() - { - $this->db->query('ALTER TABLE tracker_scalar ADD COLUMN build_results_url text NOT NULL;'); - } } diff --git a/modules/tracker/database/upgrade/1.0.4.php b/modules/tracker/database/upgrade/1.0.4.php index e4fbe71ac..699fd1464 100644 --- a/modules/tracker/database/upgrade/1.0.4.php +++ b/modules/tracker/database/upgrade/1.0.4.php @@ -30,11 +30,4 @@ public function mysql() $this->db->query("ALTER TABLE `tracker_scalar` ADD COLUMN `branch` varchar(255) NOT NULL DEFAULT '';"); $this->db->query('ALTER TABLE `tracker_scalar` ADD KEY (`branch`);'); } - - /** Upgrade a PostgreSQL database. */ - public function pgsql() - { - $this->db->query("ALTER TABLE tracker_scalar ADD COLUMN branch character varying(255) NOT NULL DEFAULT ''::character varying;"); - $this->db->query('CREATE INDEX tracker_scalar_idx_branch ON tracker_scalar (branch);'); - } } diff --git a/modules/tracker/database/upgrade/1.0.5.php b/modules/tracker/database/upgrade/1.0.5.php index 5ffc3f7bd..6148ea671 100644 --- a/modules/tracker/database/upgrade/1.0.5.php +++ b/modules/tracker/database/upgrade/1.0.5.php @@ -27,11 +27,4 @@ public function mysql() $this->db->query('ALTER TABLE `tracker_scalar` ADD COLUMN `params` text;'); $this->db->query('ALTER TABLE `tracker_scalar` ADD COLUMN `extra_urls` text;'); } - - /** Upgrade a PostgreSQL database. */ - public function pgsql() - { - $this->db->query('ALTER TABLE tracker_scalar ADD COLUMN params text;'); - $this->db->query('ALTER TABLE tracker_scalar ADD COLUMN extra_urls text;'); - } } diff --git a/modules/tracker/database/upgrade/1.2.0.php b/modules/tracker/database/upgrade/1.2.0.php index af98c8275..b23b3d0aa 100644 --- a/modules/tracker/database/upgrade/1.2.0.php +++ b/modules/tracker/database/upgrade/1.2.0.php @@ -38,20 +38,4 @@ public function mysql() ' UNIQUE KEY (`uuid`)'. ') DEFAULT CHARSET=utf8;'); } - - /** Upgrade a PostgreSQL database. */ - public function pgsql() - { - $this->db->query('ALTER TABLE tracker_scalar ADD COLUMN submission_id bigint NOT NULL DEFAULT -1::bigint;'); - $this->db->query( - 'CREATE TABLE IF NOT EXISTS "tracker_submission" ('. - ' "submission_id" serial PRIMARY KEY,'. - ' "producer_id" bigint,'. - ' "name" character varying(255) NOT NULL DEFAULT \'\'::character varying,'. - ' "uuid" character varying(255) NOT NULL DEFAULT \'\'::character varying,'. - ' "submit_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP);' - ); - $this->db->query('CREATE UNIQUE INDEX "tracker_submission_uuid" ON "tracker_submission" ("uuid");'); - $this->db->query('CREATE INDEX "tracker_submission_submit_time" ON "tracker_submission" ("submit_time");'); - } } diff --git a/modules/tracker/database/upgrade/1.2.1.php b/modules/tracker/database/upgrade/1.2.1.php index aad70a8a1..a573f37ae 100644 --- a/modules/tracker/database/upgrade/1.2.1.php +++ b/modules/tracker/database/upgrade/1.2.1.php @@ -27,11 +27,4 @@ public function mysql() $this->db->query( 'ALTER TABLE `tracker_trend` ADD COLUMN `key_metric` tinyint(4) NOT NULL DEFAULT \'0\''); } - - /** Upgrade a PostgreSQL database. */ - public function pgsql() - { - $this->db->query( - 'ALTER TABLE tracker_trend ADD COLUMN key_metric smallint NOT NULL DEFAULT 0::smallint'); - } } diff --git a/modules/tracker/database/upgrade/1.2.2.php b/modules/tracker/database/upgrade/1.2.2.php index 52031f772..66271a957 100644 --- a/modules/tracker/database/upgrade/1.2.2.php +++ b/modules/tracker/database/upgrade/1.2.2.php @@ -39,23 +39,6 @@ public function mysql() $this->db->query('ALTER TABLE `tracker_scalar` DROP `params`;'); } - /** Upgrade a PostgreSQL database. */ - public function pgsql() - { - $this->db->query( - "CREATE TABLE IF NOT EXISTS tracker_param ( - param_id serial PRIMARY KEY, - scalar_id bigint NOT NULL, - param_name character varying(255) NOT NULL, - param_type text CHECK (param_type in ('text', 'numeric')), - text_value text, - numeric_value double precision);" - ); - $this->db->query('CREATE INDEX tracker_param_param_name_idx ON tracker_param (param_name);'); - $this->migrateScalarParams(); - $this->db->query('ALTER TABLE tracker_scalar DROP COLUMN params;'); - } - /** Migrate tracker_scalar params to tracker_param. */ private function migrateScalarParams() { diff --git a/modules/tracker/database/upgrade/1.2.3.php b/modules/tracker/database/upgrade/1.2.3.php index 2ba0b8c21..043252eda 100644 --- a/modules/tracker/database/upgrade/1.2.3.php +++ b/modules/tracker/database/upgrade/1.2.3.php @@ -26,10 +26,4 @@ public function mysql() { $this->db->query('ALTER TABLE `tracker_scalar` ADD COLUMN `reproduction_command` text;'); } - - /** Upgrade a PostgreSQL database. */ - public function pgsql() - { - $this->db->query('ALTER TABLE tracker_scalar ADD COLUMN reproduction_command text;'); - } } diff --git a/modules/tracker/database/upgrade/1.2.4.php b/modules/tracker/database/upgrade/1.2.4.php index d0088b450..570fdb43f 100644 --- a/modules/tracker/database/upgrade/1.2.4.php +++ b/modules/tracker/database/upgrade/1.2.4.php @@ -58,42 +58,4 @@ public function mysql() ') DEFAULT CHARSET=utf8;' ); } - - /** Upgrade a PostgreSQL database. */ - public function pgsql() - { - $this->db->query( - 'CREATE TABLE IF NOT EXISTS "tracker_aggregate_metric" ('. - ' "aggregate_metric_id" serial PRIMARY KEY,'. - ' "aggregate_metric_spec_id" bigint NOT NULL,'. - ' "submission_id" bigint NOT NULL,'. - ' "value" double precision'. - ');' - ); - $this->db->query('CREATE INDEX "tracker_aggregate_metric_aggregate_metric_spec_id" ON "tracker_aggregate_metric" ("aggregate_metric_spec_id");'); - $this->db->query('CREATE INDEX "tracker_aggregate_metric_submission_id" ON "tracker_aggregate_metric" ("submission_id");'); - $this->db->query( - 'CREATE TABLE IF NOT EXISTS "tracker_aggregate_metric_spec" ('. - ' "aggregate_metric_spec_id" serial PRIMARY KEY,'. - ' "producer_id" bigint NOT NULL,'. - ' "branch" character varying(255) NOT NULL,'. - ' "name" character varying(255) NOT NULL,'. - ' "description" character varying(255) NOT NULL,'. - ' "spec" text,'. - ' "value" double precision,'. - ' "comparison" character varying(2) NOT NULL'. - ');' - ); - $this->db->query('CREATE INDEX "tracker_aggregate_metric_spec_producer_id" ON "tracker_aggregate_metric_spec" ("producer_id");'); - $this->db->query('CREATE INDEX "tracker_aggregate_metric_spec_branch" ON "tracker_aggregate_metric_spec" ("branch");'); - $this->db->query( - 'CREATE TABLE IF NOT EXISTS "tracker_user2aggregate_metric_spec" ('. - ' "id" serial PRIMARY KEY,'. - ' "user_id" bigint NOT NULL,'. - ' "aggregate_metric_spec_id" bigint NOT NULL,'. - ' PRIMARY_KEY("user_id", "aggregate_metric_spec_id")'. - ');' - ); - $this->db->query('CREATE INDEX "tracker_user2aggregate_metric_spec_ams_id_idx" ON "tracker_user2aggregate_metric_spec" ("aggregate_metric_spec_id");'); - } } diff --git a/modules/tracker/database/upgrade/2.0.0.php b/modules/tracker/database/upgrade/2.0.0.php new file mode 100644 index 000000000..2bdc3f5d5 --- /dev/null +++ b/modules/tracker/database/upgrade/2.0.0.php @@ -0,0 +1,37 @@ +db->query( + 'CREATE TABLE IF NOT EXISTS `tracker_aggregate_metric_notification` ('. + ' `aggregate_metric_notification_id` bigint(20) NOT NULL AUTO_INCREMENT,'. + ' `aggregate_metric_spec_id` bigint(20) NOT NULL,'. + " `branch` varchar(255) NOT NULL DEFAULT '',". + ' `value` double,'. + " `comparison` varchar(2) NOT NULL DEFAULT '',". + ' PRIMARY KEY (`aggregate_metric_notification_id`),'. + ' KEY (`aggregate_metric_spec_id`),'. + ' KEY (`branch`)'. + ') DEFAULT CHARSET=utf8;' + ); + + $this->db->query( + 'CREATE TABLE IF NOT EXISTS `tracker_user2aggregate_metric_notification` ('. + ' `user_id` bigint(20) NOT NULL,'. + ' `aggregate_metric_notification_id` bigint(20) NOT NULL,'. + ' PRIMARY KEY (`user_id`, `aggregate_metric_notification_id`)'. + ') DEFAULT CHARSET=utf8;' + ); + + // Migrate AMS (comparison, value, branch) to tracker_aggregate_metric_notification. + $this->db->query( + 'INSERT INTO `tracker_aggregate_metric_notification` '. + ' (`aggregate_metric_spec_id`, `branch`, `value`, `comparison`) '. + 'SELECT '. + ' `aggregate_metric_spec_id`, `branch`, `value`, `comparison` '. + 'from `tracker_aggregate_metric_spec`;' + ); + + // Migrate notified users. + $this->db->query( + 'INSERT INTO `tracker_user2aggregate_metric_notification` '. + ' (`user_id`, `aggregate_metric_notification_id`) '. + 'SELECT '. + ' `user_id`, `aggregate_metric_notification_id` '. + 'FROM `tracker_aggregate_metric_notification` AS `amn`, `tracker_user2aggregate_metric_spec` AS `u2ams` WHERE '. + ' `amn`.`aggregate_metric_spec_id` = `u2ams`.`aggregate_metric_spec_id`;' + ); + + // Drop migrated columns and tables. + $this->db->query( + 'ALTER TABLE `tracker_aggregate_metric_spec` '. + ' DROP COLUMN `branch`, '. + ' DROP COLUMN `comparison`, '. + ' DROP COLUMN `value`;' + ); + + $this->db->query('DROP TABLE `tracker_user2aggregate_metric_spec`;'); + } +} diff --git a/modules/tracker/models/base/AggregateMetricNotificationModelBase.php b/modules/tracker/models/base/AggregateMetricNotificationModelBase.php new file mode 100644 index 000000000..f8bac87b8 --- /dev/null +++ b/modules/tracker/models/base/AggregateMetricNotificationModelBase.php @@ -0,0 +1,93 @@ +_name = 'tracker_aggregate_metric_notification'; + $this->_daoName = 'AggregateMetricNotificationDao'; + $this->_key = 'aggregate_metric_notification_id'; + $this->_mainData = array( + 'aggregate_metric_notification_id' => array('type' => MIDAS_DATA), + 'aggregate_metric_spec_id' => array('type' => MIDAS_DATA), + 'branch' => array('type' => MIDAS_DATA), + 'value' => array('type' => MIDAS_DATA), + 'comparison' => array('type' => MIDAS_DATA), + 'aggregate_metric_spec' => array( + 'type' => MIDAS_MANY_TO_ONE, + 'model' => 'AggregateMetricSpec', + 'module' => $this->moduleName, + 'parent_column' => 'aggregate_metric_spec_id', + 'child_column' => 'aggregate_metric_spec_id', + ), + ); + + $this->initialize(); + } + + /** + * Create a user notification tied to the aggregate metric notification. + * + * @param Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao aggregateMetricNotification DAO + * @param UserDao $userDao user DAO + * @return bool true if the notification could be created, false otherwise + */ + abstract public function createUserNotification($aggregateMetricNotificationDao, $userDao); + + /** + * Delete a user notification tied to the aggregate metric notification. + * + * @param Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao aggregateMetricNotification DAO + * @param UserDao $userDao user DAO + * @return bool true if the user and aggregate metric notification are valid and a + * notification does not exist for this user and aggregate metric notification upon + * returning, false otherwise + */ + abstract public function deleteUserNotification($aggregateMetricNotificationDao, $userDao); + + /** + * Return a list of User Daos for all users with notifications on this aggregate metric notification. + * + * @param Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao aggregateMetricNotification DAO + * @return false|array of UserDao for all users with notification on the passed in $aggregateMetricNotificationDao, + * or false if the passed in notification is invalid + */ + abstract public function getAllNotifiedUsers($aggregateMetricNotificationDao); + + /** + * Return a list of Jobs scheduled to notify users, if the passed aggregate metric + * is beyond the threshold of any notifications tied to the aggregate metric spec + * that generated the aggregate metric. + * + * @param Tracker_AggregateMetricNotificationDao $aggregateMetricNotification + * @return false|array of Scheduler_JobDao for all users with a notification + * created, which will only be populated if the aggregate metric is beyond + * the threshold defined on any aggregate metric notification tied to the + * aggregate metric spec that generated the aggregate metric and there exist + * users to be notified on the aggregate metric notification, + * or false if the inputs are invalid. + */ + abstract public function scheduleNotificationJobs($aggregateMetricDao); +} diff --git a/modules/tracker/models/base/AggregateMetricSpecModelBase.php b/modules/tracker/models/base/AggregateMetricSpecModelBase.php index 24e55985a..74a95ffee 100644 --- a/modules/tracker/models/base/AggregateMetricSpecModelBase.php +++ b/modules/tracker/models/base/AggregateMetricSpecModelBase.php @@ -32,7 +32,6 @@ public function __construct() $this->_mainData = array( 'aggregate_metric_spec_id' => array('type' => MIDAS_DATA), 'producer_id' => array('type' => MIDAS_DATA), - 'branch' => array('type' => MIDAS_DATA), 'name' => array('type' => MIDAS_DATA), 'description' => array('type' => MIDAS_DATA), 'spec' => array('type' => MIDAS_DATA), @@ -50,61 +49,16 @@ public function __construct() $this->initialize(); } - /** - * Create a user notification tied to the aggregate metric spec. - * - * @param Tracker_AggregateMetricSpecDao $aggregateMetricSpecDao aggregateMetricSpec DAO - * @param UserDao $userDao user DAO - * @return bool true if the notification could be created, false otherwise - */ - abstract public function createUserNotification($aggregateMetricSpecDao, $userDao); - - /** - * Delete a user notification tied to the aggregate metric spec. - * - * @param Tracker_AggregateMetricSpecDao $aggregateMetricSpecDao aggregateMetricSpec DAO - * @param UserDao $userDao user DAO - * @return bool true if the user and aggregate metric spec are valid and a - * notification does not exist for this user and aggregate metric spec upon - * returning, false otherwise - */ - abstract public function deleteUserNotification($aggregateMetricSpecDao, $userDao); - - /** - * Return a list of User Daos for all users with notifications on this aggregate metric spec. - * - * @param Tracker_AggregateMetricSpecDao $aggregateMetricSpecDao aggregateMetricSpec DAO - * @return false|array of UserDao for all users with notification on the passed in $aggregateMetricSpecDao, - * or false if the passed in spec is invalid - */ - abstract public function getAllNotifiedUsers($aggregateMetricSpecDao); - - /** - * Return a list of Jobs scheduled to notify users that the passed aggregate metric is above - * the threshold defined in the passed aggregate metric spec. - * - * @param Tracker_AggregateMetricSpecDao $aggregateMetricSpecDao aggregateMetricSpec DAO - * @param Tracker_AggregateMetricDao $aggregateMetricDao aggregateMetric DAO - * @return false|array of Scheduler_JobDao for all users with a notification created, which will only - * be populated if the aggregate metric is above the threshold defined on the aggregate metric spec and - * there exist users to be notified on the aggregate metric spec, or false if the inputs are invalid. - */ - abstract public function scheduleNotificationJobs($aggregateMetricSpecDao, $aggregateMetricDao); - /** * Create an AggregateMetricSpecDao from the inputs. * * @param Tracker_ProducerDao $producerDao producer DAO * @param string $name the name of the aggregate metric spec * @param string $spec the spec for the aggregate metric spec - * @param string $branch the branch of the aggregate metric spec (defaults to 'master') * @param false | string $description the description for the aggregate metric spec - * @param false | string $value the value for the aggregate metric spec threshold - * @param false | string $comparison the comparison for the aggregate metric spec threshold, - * one of ['>', '<', '>=', '<', '<=', '==', '!='] * @return false | Tracker_AggregateMetricSpecDao created from inputs */ - public function createAggregateMetricSpec($producerDao, $name, $spec, $branch = 'master', $description = false, $value = false, $comparison = false) + public function createAggregateMetricSpec($producerDao, $name, $spec, $description = false) { if (is_null($producerDao) || $producerDao === false) { return false; @@ -113,7 +67,6 @@ public function createAggregateMetricSpec($producerDao, $name, $spec, $branch = /** @var Tracker_AggregateMetricSpecDao $aggregateMetricSpecDao */ $aggregateMetricSpecDao = MidasLoader::newDao('AggregateMetricSpecDao', 'tracker'); $aggregateMetricSpecDao->setProducerId($producerDao->getProducerId()); - $aggregateMetricSpecDao->setBranch($branch); $aggregateMetricSpecDao->setName($name); $aggregateMetricSpecDao->setSpec($spec); if ($description) { @@ -121,14 +74,6 @@ public function createAggregateMetricSpec($producerDao, $name, $spec, $branch = } else { $aggregateMetricSpecDao->setDescription(''); } - if ($value) { - $aggregateMetricSpecDao->setValue($value); - } - if ($comparison) { - $aggregateMetricSpecDao->setComparison($comparison); - } else { - $aggregateMetricSpecDao->setComparison(''); - } $this->save($aggregateMetricSpecDao); return $aggregateMetricSpecDao; diff --git a/modules/tracker/models/base/ParamModelBase.php b/modules/tracker/models/base/ParamModelBase.php index 4705b7bc9..b33497267 100644 --- a/modules/tracker/models/base/ParamModelBase.php +++ b/modules/tracker/models/base/ParamModelBase.php @@ -30,17 +30,17 @@ public function __construct() $this->_key = 'param_id'; $this->_mainData = array( 'param_id' => array('type' => MIDAS_DATA), - 'scalar_id' => array('type' => MIDAS_DATA), + 'submission_id' => array('type' => MIDAS_DATA), 'param_name' => array('type' => MIDAS_DATA), 'param_type' => array('type' => MIDAS_DATA), 'text_value' => array('type' => MIDAS_DATA), 'numeric_value' => array('type' => MIDAS_DATA), - 'scalar' => array( + 'submission' => array( 'type' => MIDAS_MANY_TO_ONE, - 'model' => 'Scalar', + 'model' => 'Submission', 'module' => $this->moduleName, - 'parent_column' => 'scalar_id', - 'child_column' => 'scalar_id', + 'parent_column' => 'submission_id', + 'child_column' => 'submission_id', ), ); diff --git a/modules/tracker/models/base/ScalarModelBase.php b/modules/tracker/models/base/ScalarModelBase.php index 9be7c0210..1f93098a3 100644 --- a/modules/tracker/models/base/ScalarModelBase.php +++ b/modules/tracker/models/base/ScalarModelBase.php @@ -31,16 +31,17 @@ public function __construct() $this->_mainData = array( 'scalar_id' => array('type' => MIDAS_DATA), 'trend_id' => array('type' => MIDAS_DATA), - 'user_id' => array('type' => MIDAS_DATA), 'submission_id' => array('type' => MIDAS_DATA), - 'official' => array('type' => MIDAS_DATA), - 'build_results_url' => array('type' => MIDAS_DATA), - 'extra_urls' => array('type' => MIDAS_DATA), - 'branch' => array('type' => MIDAS_DATA), - 'submit_time' => array('type' => MIDAS_DATA), + /** + * submit_time, branch, and official are not actually present in + * the scalar table, but they are present here to be populated in + * the DAO when scalars are retrieved via a join query with + * submission. + */ + 'submit_time' => array('type' => MIDAS_DATA), // from submission + 'branch' => array('type' => MIDAS_DATA), // from submission + 'official' => array('type' => MIDAS_DATA), // from submission 'value' => array('type' => MIDAS_DATA), - 'producer_revision' => array('type' => MIDAS_DATA), - 'reproduction_command' => array('type' => MIDAS_DATA), 'trend' => array( 'type' => MIDAS_MANY_TO_ONE, 'model' => 'Trend', @@ -55,57 +56,11 @@ public function __construct() 'parent_column' => 'submission_id', 'child_column' => 'submission_id', ), - 'user' => array( - 'type' => MIDAS_MANY_TO_ONE, - 'model' => 'User', - 'parent_column' => 'user_id', - 'child_column' => 'user_id', - ), - 'params' => array( - 'type' => MIDAS_ONE_TO_MANY, - 'model' => 'Param', - 'module' => $this->moduleName, - 'parent_column' => 'scalar_id', - 'child_column' => 'scalar_id', - ), ); $this->initialize(); } - /** - * Associate the given scalar and item. - * - * @param Tracker_ScalarDao $scalarDao scalar DAO - * @param ItemDao $itemDao item DAO - * @param string $label label - */ - abstract public function associateItem($scalarDao, $itemDao, $label); - - /** - * Return the items associated with the given scalar. - * - * @param Tracker_ScalarDao $scalarDao scalar DAO - * @return array array of associative arrays with keys "item" and "label" - */ - abstract public function getAssociatedItems($scalarDao); - - /** - * Return any other scalars from the same submission as the given scalar. - * - * @param Tracker_ScalarDao $scalarDao scalar DAO - * @return array scalar DAOs - */ - abstract public function getOtherScalarsFromSubmission($scalarDao); - - /** - * Return any other values from the same submission as the given scalar. - * - * @param Tracker_ScalarDao $scalarDao scalar DAO - * @return array associative array with keys equal to the metric names - */ - abstract public function getOtherValuesFromSubmission($scalarDao); - /** * Return a scalar given a trend id, submit time, and user id. * @@ -117,88 +72,32 @@ abstract public function getOtherValuesFromSubmission($scalarDao); abstract public function getByTrendAndTimestamp($trendId, $submitTime, $userId = null); /** - * Return all distinct branch names of revisions producing scalars. + * Return any other scalars from the same submission as the given scalar. * - * @return array branch names + * @param Tracker_ScalarDao $scalarDao scalar DAO + * @return array scalar DAOs */ - abstract public function getDistinctBranches(); + abstract public function getOtherScalarsFromSubmission($scalarDao); /** - * Add a new scalar to the trend. If overwrite is true, and a scalar already exists on the trend with the same - * submit time and user, then this will replace that scalar. + * Add a new scalar to the trend. * * @param Tracker_TrendDao $trendDao trend DAO - * @param string $submitTime submit time - * @param string $producerRevision producer revision - * @param float $value scalar value - * @param UserDao $userDao user DAO - * @param bool $overwrite true if a scalar with the same trend, submit time, and user should be overwritten - * @param bool $official true if the submission containing the scalar should be official - * @param string $buildResultsUrl build results URL - * @param null|string $branch branch name - * @param null|string|array $params parameters - * @param null|string|array $extraUrls extra URLs - * @param null|string $reproductionCommand the command to reproduce this run + * @param Tracker_SubmissionDao $submissionDao submission DAO + * @param float $value * @return Tracker_ScalarDao scalar DAO */ - public function addToTrend( - $trendDao, - $submitTime, - $submissionId, - $producerRevision, - $value, - $userDao, - $overwrite = true, - $official = true, - $buildResultsUrl = '', - $branch = '', - $params = null, - $extraUrls = null, - $reproductionCommand = null - ) { - if ($overwrite === true) { - $scalarDao = $this->getByTrendAndTimestamp($trendDao->getKey(), $submitTime, $userDao->getKey()); - - if ($scalarDao !== false) { - $this->delete($scalarDao); - } - } - - if (empty($extraUrls)) { - $extraUrls = null; - } elseif (is_array($extraUrls)) { - $extraUrls = json_encode($extraUrls); - } - - $userId = (is_null($userDao) || $userDao === false) ? -1 : $userDao->getKey(); + public function addToTrend($trendDao, $submissionDao, $value) + { /** @var Tracker_ScalarDao $scalarDao */ $scalarDao = MidasLoader::newDao('ScalarDao', $this->moduleName); - $scalarDao->setSubmissionId($submissionId); + + $scalarDao->setSubmissionId($submissionDao->getKey()); $scalarDao->setTrendId($trendDao->getKey()); - $scalarDao->setSubmitTime($submitTime); - $scalarDao->setProducerRevision($producerRevision); $scalarDao->setValue($value); - $scalarDao->setUserId($userId); - $scalarDao->setOfficial((int) $official); - $scalarDao->setBuildResultsUrl($buildResultsUrl); - $scalarDao->setBranch(trim($branch)); - $scalarDao->setExtraUrls($extraUrls); - $scalarDao->setReproductionCommand($reproductionCommand); $this->save($scalarDao); - if (!empty($params) && is_array($params)) { - $paramModel = MidasLoader::loadModel('Param', $this->moduleName); - foreach ($params as $paramName => $paramValue) { - /** @var Tracker_ParamDao $paramDao */ - $paramDao = MidasLoader::newDao('ParamDao', $this->moduleName); - $paramDao->setScalarId($scalarDao->getScalarId()); - $paramDao->setParamName($paramName); - $paramDao->setParamValue($paramValue); - $paramModel->save($paramDao); - } - } - return $scalarDao; } diff --git a/modules/tracker/models/base/SubmissionModelBase.php b/modules/tracker/models/base/SubmissionModelBase.php index 586e040cd..e43216615 100644 --- a/modules/tracker/models/base/SubmissionModelBase.php +++ b/modules/tracker/models/base/SubmissionModelBase.php @@ -36,6 +36,13 @@ public function __construct() 'name' => array('type' => MIDAS_DATA), 'uuid' => array('type' => MIDAS_DATA), 'submit_time' => array('type' => MIDAS_DATA), + 'user_id' => array('type' => MIDAS_DATA), + 'official' => array('type' => MIDAS_DATA), + 'build_results_url' => array('type' => MIDAS_DATA), + 'extra_urls' => array('type' => MIDAS_DATA), + 'branch' => array('type' => MIDAS_DATA), + 'producer_revision' => array('type' => MIDAS_DATA), + 'reproduction_command' => array('type' => MIDAS_DATA), 'producer' => array( 'type' => MIDAS_MANY_TO_ONE, 'model' => 'Producer', @@ -43,20 +50,53 @@ public function __construct() 'parent_column' => 'producer_id', 'child_column' => 'producer_id', ), + 'params' => array( + 'type' => MIDAS_ONE_TO_MANY, + 'model' => 'Param', + 'module' => $this->moduleName, + 'parent_column' => 'submission_id', + 'child_column' => 'submission_id', + ), + 'user' => array( + 'type' => MIDAS_MANY_TO_ONE, + 'model' => 'User', + 'parent_column' => 'user_id', + 'child_column' => 'user_id', + ), ); $this->initialize(); } + /** + * Associate the given submission and item. + * + * @param Tracker_SubmissionDao $submissionDao submission DAO + * @param ItemDao $itemDao item DAO + * @param string $label label + * @param Tracker_TrendgroupDao $trendgroupDao trendgroup DAO + */ + abstract public function associateItem($submissionDao, $itemDao, $label, $trendgroupDao); + + /** + * Return the items associated with the given submission. + * + * @param Tracker_SubmissionDao $submissionDao submission DAO + * @param Tracker_TrendgroupDao $trendgroupDao trendgroup DAO + * @return array array of associative arrays with keys "item" and "label" + */ + abstract public function getAssociatedItems($submissionDao, $trendgroupDao); + /** * Create a submission. * * @param Tracker_ProducerDao $producerDao the producer to which the submission was submitted * @param string $uuid the uuid of the submission * @param string $name the name of the submission (defaults to '') + * @param array $params the parameters used to generate the submission (defaults to null) * @return Tracker_SubmissionDao */ - abstract public function createSubmission($producerDao, $uuid, $name = ''); + abstract public function createSubmission($producerDao, $uuid, $name = '', $params = null); /** * Get a submission from its uuid. @@ -84,12 +124,23 @@ abstract public function getOrCreateSubmission($producerDao, $uuid); abstract public function getSubmissionsByProducer($producerDao); /** - * Get the scalars associated with a submission. + * Return the scalars for a given submission. + * * @param Tracker_SubmissionDao $submissionDao submission DAO * @param bool $key whether to only retrieve scalars of key trends - * @return array submission DAOs + * @param bool|false|Tracker_TrendgroupDao $trendGroup dao of trend group to limit scalars + * @return array scalar DAOs + * @throws Zend_Exception + */ + abstract public function getScalars($submissionDao, $key = false, $trendGroup = false); + + /** + * Return the values (trend name, value, and unit in an array) from a given submission. + * + * @param Tracker_SubmissionDao $submissionDao submission DAO + * @return array associative array with keys equal to the metric names */ - abstract public function getScalars($submissionDao, $key = false); + abstract public function getValuesFromSubmission($submissionDao); /** * Get the single latest submission associated with a given producer. @@ -114,4 +165,11 @@ abstract public function getLatestSubmissionByProducerDateAndBranch($producerDao * @return array Tracker_TrendDaos */ abstract public function getTrends($submissionDao, $key = true); + + /** + * Return all distinct branch names of revisions producing submissions. + * + * @return array branch names + */ + abstract public function getDistinctBranches(); } diff --git a/modules/tracker/models/base/TrendModelBase.php b/modules/tracker/models/base/TrendModelBase.php index 2027ab013..0a25df14a 100644 --- a/modules/tracker/models/base/TrendModelBase.php +++ b/modules/tracker/models/base/TrendModelBase.php @@ -30,38 +30,17 @@ public function __construct() $this->_key = 'trend_id'; $this->_mainData = array( 'trend_id' => array('type' => MIDAS_DATA), - 'producer_id' => array('type' => MIDAS_DATA), 'metric_name' => array('type' => MIDAS_DATA), 'display_name' => array('type' => MIDAS_DATA), 'unit' => array('type' => MIDAS_DATA), - 'config_item_id' => array('type' => MIDAS_DATA), - 'test_dataset_id' => array('type' => MIDAS_DATA), - 'truth_dataset_id' => array('type' => MIDAS_DATA), 'key_metric' => array('type' => MIDAS_DATA), - 'producer' => array( + 'trendgroup_id' => array('type' => MIDAS_DATA), + 'trendgroup' => array( 'type' => MIDAS_MANY_TO_ONE, - 'model' => 'Producer', + 'model' => 'Trendgroup', 'module' => $this->moduleName, - 'parent_column' => 'producer_id', - 'child_column' => 'producer_id', - ), - 'config_item' => array( - 'type' => MIDAS_MANY_TO_ONE, - 'model' => 'Item', - 'parent_column' => 'config_item_id', - 'child_column' => 'item_id', - ), - 'test_dataset_item' => array( - 'type' => MIDAS_MANY_TO_ONE, - 'model' => 'Item', - 'parent_column' => 'test_dataset_id', - 'child_column' => 'item_id', - ), - 'truth_dataset_item' => array( - 'type' => MIDAS_MANY_TO_ONE, - 'model' => 'Item', - 'parent_column' => 'truth_dataset_id', - 'child_column' => 'item_id', + 'parent_column' => 'trendgroup_id', + 'child_column' => 'trendgroup_id', ), 'scalars' => array( 'type' => MIDAS_ONE_TO_MANY, @@ -76,17 +55,16 @@ public function __construct() } /** - * Return the trend DAO that matches the given the producer id, metric name, associated items, and unit. + * Return the trend DAO that matches the given the producer id, metric name, and associated items. * * @param int $producerId producer id * @param string $metricName metric name * @param null|int $configItemId configuration item id * @param null|int $testDatasetId test dataset item id * @param null|int $truthDatasetId truth dataset item id - * @param false|string $unit (Optional) scalar value unit, defaults to false * @return false|Tracker_TrendDao trend DAO or false if none exists */ - abstract public function getMatch($producerId, $metricName, $configItemId, $testDatasetId, $truthDatasetId, $unit = false); + abstract public function getMatch($producerId, $metricName, $configItemId, $testDatasetId, $truthDatasetId); /** * Return the trend DAOs that match the given associative array of database columns and values. @@ -109,24 +87,14 @@ abstract public function getAllByParams($params); abstract public function getScalars($trendDao, $startDate = null, $endDate = null, $userId = null, $branch = null); /** - * Return all trends corresponding to the given producer. They will be grouped by distinct - * config/test/truth dataset combinations. + * Return all trends corresponding to the given producer. They will be grouped by their trend + * group and returned along with the test, truth, and config item DAOs. * * @param Tracker_ProducerDao $producerDao producer DAO * @param bool $onlyKey whether to return only key trends - * @return array + * @return array array of associative arrays with keys "configItem", "testDataset", "truthDataset", and "trends" */ - abstract public function getTrendsGroupByDatasets($producerDao, $onlyKey = false); - - /** - * Return all distinct branch names producing scalars, tied to a specific - * producer, for trends that are key_metrics, and matching a trend metric_name. - * - * @param int $producerId producer id - * @param string $metricName trend metric_name - * @return array branch names - */ - abstract public function getDistinctBranchesForMetricName($producerId, $metricName); + abstract public function getTrendsByGroup($producerDao, $onlyKey = false); /** * Save the given trend. Ensure that null values are explicitly set in the database. @@ -154,12 +122,19 @@ public function save($trendDao) */ public function createIfNeeded($producerId, $metricName, $configItemId, $testDatasetId, $truthDatasetId, $unit = false) { - $trendDao = $this->getMatch($producerId, $metricName, $configItemId, $testDatasetId, $truthDatasetId, $unit); + $trendDao = $this->getMatch($producerId, $metricName, $configItemId, $testDatasetId, $truthDatasetId); if ($trendDao === false) { + + /** @var Tracker_TrendGroupModel $trendGroupModel */ + $trendGroupModel = MidasLoader::loadModel('Trendgroup', $this->moduleName); + /** @var Tracker_TrendDao $trendDao */ $trendDao = MidasLoader::newDao('TrendDao', $this->moduleName); - $trendDao->setProducerId($producerId); + + /** @var Tracker_TrendGroupDao $trendGroupDao */ + $trendGroupDao = $trendGroupModel->createIfNeeded($producerId, $configItemId, $testDatasetId, $truthDatasetId); + $trendDao->setMetricName($metricName); $trendDao->setDisplayName($metricName); if ($unit === false) { @@ -167,17 +142,7 @@ public function createIfNeeded($producerId, $metricName, $configItemId, $testDat } $trendDao->setUnit($unit); - if (!is_null($configItemId)) { - $trendDao->setConfigItemId($configItemId); - } - - if (!is_null($testDatasetId)) { - $trendDao->setTestDatasetId($testDatasetId); - } - - if (!is_null($truthDatasetId)) { - $trendDao->setTruthDatasetId($truthDatasetId); - } + $trendDao->setTrendgroupId($trendGroupDao->getKey()); // Our pgsql code can't handle ACTUAL booleans :deep_sigh: $trendDao->setKeyMetric('0'); @@ -253,7 +218,7 @@ public function policyCheck($trendDao, $userDao = null, $policy = MIDAS_POLICY_R /** @var Tracker_ProducerModel $producerModel */ $producerModel = MidasLoader::loadModel('Producer', $this->moduleName); - $producerDao = $trendDao->getProducer(); + $producerDao = $trendDao->getTrendgroup()->getProducer(); return $producerModel->policyCheck($producerDao, $userDao, $policy); } diff --git a/modules/tracker/models/base/TrendgroupModelBase.php b/modules/tracker/models/base/TrendgroupModelBase.php new file mode 100644 index 000000000..c0d062f73 --- /dev/null +++ b/modules/tracker/models/base/TrendgroupModelBase.php @@ -0,0 +1,85 @@ +_name = 'tracker_trendgroup'; + $this->_key = 'trendgroup_id'; + $this->_mainData = array( + 'trendgroup_id' => array('type' => MIDAS_DATA), + 'producer_id' => array('type' => MIDAS_DATA), + 'config_item_id' => array('type' => MIDAS_DATA), + 'test_dataset_id' => array('type' => MIDAS_DATA), + 'truth_dataset_id' => array('type' => MIDAS_DATA), + 'producer' => array( + 'type' => MIDAS_MANY_TO_ONE, + 'model' => 'Producer', + 'module' => $this->moduleName, + 'parent_column' => 'producer_id', + 'child_column' => 'producer_id', + ), + 'config_item' => array( + 'type' => MIDAS_MANY_TO_ONE, + 'model' => 'Item', + 'parent_column' => 'config_item_id', + 'child_column' => 'item_id', + ), + 'test_dataset_item' => array( + 'type' => MIDAS_MANY_TO_ONE, + 'model' => 'Item', + 'parent_column' => 'test_dataset_id', + 'child_column' => 'item_id', + ), + 'truth_dataset_item' => array( + 'type' => MIDAS_MANY_TO_ONE, + 'model' => 'Item', + 'parent_column' => 'truth_dataset_id', + 'child_column' => 'item_id', + ), + 'trends' => array( + 'type' => MIDAS_ONE_TO_MANY, + 'model' => 'Trend', + 'module' => $this->moduleName, + 'parent_column' => 'trendgroup_id', + 'child_column' => 'trendgroup_id', + ), + ); + + $this->initialize(); + } + + /** + * Return the trendgroup DAO that matches the given producer id and associated item if the trendgroup exists. + * Otherwise, create the trend DAO. + * + * @param int $producerId producer id + * @param null|int $configItemId configuration item id + * @param null|int $testDatasetId test dataset item id + * @param null|int $truthDatasetId truth dataset item id + * @return Tracker_TrendgroupDao trend DAO + */ + abstract public function createIfNeeded($producerId, $configItemId, $testDatasetId, $truthDatasetId); +} diff --git a/modules/tracker/models/dao/AggregateMetricNotificationDao.php b/modules/tracker/models/dao/AggregateMetricNotificationDao.php new file mode 100644 index 000000000..b0d04e5f5 --- /dev/null +++ b/modules/tracker/models/dao/AggregateMetricNotificationDao.php @@ -0,0 +1,42 @@ +database->select()->setIntegrityCheck(false) ->from('tracker_trend', array('trend_id')) + ->join('tracker_trendgroup', 'tracker_trendgroup.trendgroup_id=tracker_trend.trendgroup_id') ->where('key_metric = ?', 1) ->where('producer_id = ?', $aggregateMetricSpecDao->getProducerId()) ->where('metric_name = ?', $metricName); $rows = $this->database->fetchAll($sql); if (count($rows) === 0) { return false; - }; + } $trendIds = array(); /** @var Zend_Db_Table_Row_Abstract $row */ foreach ($rows as $row) { @@ -105,14 +106,18 @@ public function getAggregateMetricInputValuesForSubmission($aggregateMetricSpecD // Get all the scalar values from these trends in the submission. $sql = $this->database->select()->setIntegrityCheck(false) - ->from('tracker_scalar', array('value')) - ->where('submission_id = ?', $submissionDao->getSubmissionId()) - ->where('branch = ?', $aggregateMetricSpecDao->getBranch()) - ->where('trend_id IN (?)', $trendIds); + ->from('tracker_scalar') + ->join( + 'tracker_submission', + 'tracker_scalar.submission_id = tracker_submission.submission_id', + array() + ) + ->where('tracker_submission.submission_id = ?', $submissionDao->getKey()) + ->where('tracker_scalar.trend_id IN (?)', $trendIds); $rows = $this->database->fetchAll($sql); if (count($rows) === 0) { return false; - }; + } $values = array(); /** @var Zend_Db_Table_Row_Abstract $row */ foreach ($rows as $row) { @@ -304,7 +309,7 @@ public function getAggregateMetricsForSubmissions($aggregateMetricSpecDao, $subm $rows = $this->database->fetchAll($sql); if (count($rows) === 0) { return false; - }; + } $aggregateMetricDaosBySubmissionId = array(); /** @var Zend_Db_Table_Row_Abstract $row */ foreach ($rows as $row) { @@ -360,12 +365,10 @@ public function getAggregateMetricsSeries($producerDao, $lastDate = false, $days ->join(array('u' => 'tracker_submission'), 'am.submission_id = u.submission_id', array()) - // TODO Tracker 2.0 delete this join >> ->join(array('ams' => 'tracker_aggregate_metric_spec'), 'ams.aggregate_metric_spec_id = am.aggregate_metric_spec_id', array()) - // << TODO Tracker 2.0 delete this join - ->where('ams.branch = ?', $branch) // TODO Tracker 2.0 u.branch = ? + ->where('u.branch = ?', $branch) ->where('u.producer_id = ?', $producerDao->getProducerId()) ->where('u.submit_time > ?', $firstDate->format('Y-m-d H:i:s')) ->where('u.submit_time <= ?', $lastDate) @@ -376,7 +379,7 @@ public function getAggregateMetricsSeries($producerDao, $lastDate = false, $days $rows = $this->database->fetchAll($sql); if (count($rows) === 0) { return array(); - }; + } $metricsSeries = array(); /** @var Zend_Db_Table_Row_Abstract $row */ diff --git a/modules/tracker/models/pdo/AggregateMetricNotificationModel.php b/modules/tracker/models/pdo/AggregateMetricNotificationModel.php new file mode 100644 index 000000000..b2c02fdd0 --- /dev/null +++ b/modules/tracker/models/pdo/AggregateMetricNotificationModel.php @@ -0,0 +1,220 @@ +database->select()->setIntegrityCheck(false) + ->from('tracker_user2aggregate_metric_notification') + ->where('aggregate_metric_notification_id = ?', $aggregateMetricNotificationDao->getAggregateMetricNotificationId()) + ->where('user_id = ?', $userDao->getUserId()); + /** @var Zend_Db_Table_Row_Abstract $row */ + $row = $this->database->fetchRow($sql); + if (!is_null($row)) { + return true; + } else { + $data = array( + 'aggregate_metric_notification_id' => $aggregateMetricNotificationDao->getAggregateMetricNotificationId(), + 'user_id' => $userDao->getUserId(), + ); + $this->database->getdb()->insert('tracker_user2aggregate_metric_notification', $data); + + return true; + } + } + + /** + * Delete a user notification tied to the aggregate metric notification. + * + * @param Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao aggregateMetricNotification DAO + * @param UserDao $userDao user DAO + * @return bool true if the user and aggregate metric notification are valid and a + * notification does not exist for this user and aggregate metric notification upon + * returning, false otherwise + */ + public function deleteUserNotification($aggregateMetricNotificationDao, $userDao) + { + if (is_null($aggregateMetricNotificationDao) || $aggregateMetricNotificationDao === false) { + return false; + } + if (is_null($userDao) || $userDao === false) { + return false; + } + $this->database->getDB()->delete('tracker_user2aggregate_metric_notification', array( + 'aggregate_metric_notification_id = ?' => $aggregateMetricNotificationDao->getAggregateMetricNotificationId(), + 'user_id = ?' => $userDao->getUserId(), + )); + + return true; + } + + /** + * Return a list of User Daos for all users with notifications on this aggregate metric notification. + * + * @param Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao aggregateMetricNotification DAO + * @return false|array of UserDao for all users with notification on the passed in $aggregateMetricNotificationDao, + * or false if the passed in notification is invalid + */ + public function getAllNotifiedUsers($aggregateMetricNotificationDao) + { + if (is_null($aggregateMetricNotificationDao) || $aggregateMetricNotificationDao === false) { + return false; + } + $sql = $this->database->select()->setIntegrityCheck(false) + ->from('tracker_user2aggregate_metric_notification', array('user_id')) + ->where('aggregate_metric_notification_id = ?', $aggregateMetricNotificationDao->getAggregateMetricNotificationId()); + $rows = $this->database->fetchAll($sql); + + $userDaos = array(); + /** @var userModel $userModel */ + $userModel = MidasLoader::loadModel('User'); + /** @var Zend_Db_Table_Row_Abstract $row */ + foreach ($rows as $row) { + $userDaos[] = $userModel->load($row['user_id']); + } + + return $userDaos; + } + + /** + * Return a list of Jobs scheduled to notify users, if the passed aggregate metric + * is beyond the threshold of any notifications tied to the aggregate metric spec + * that generated the aggregate metric. + * + * @param Tracker_AggregateMetricNotificationDao $aggregateMetricNotification + * @return false|array of Scheduler_JobDao for all users with a notification + * created, which will only be populated if the aggregate metric is beyond + * the threshold defined on any aggregate metric notification tied to the + * aggregate metric spec that generated the aggregate metric and there exist + * users to be notified on the aggregate metric notification, + * or false if the inputs are invalid. + */ + public function scheduleNotificationJobs($aggregateMetricDao) + { + if (is_null($aggregateMetricDao) || $aggregateMetricDao === false) { + return false; + } + + /** @var string $branch */ + $branch = $aggregateMetricDao->getSubmission()->getBranch(); + /** @var Tracker_AggregateMetricSpecDao $aggregateMetricSpecDao */ + $aggregateMetricSpecDao = $aggregateMetricDao->getAggregateMetricSpec(); + $jobs = array(); + + // Get all notifications tied to that spec and branch. + $sql = $this->database->select()->setIntegrityCheck(false) + ->from('tracker_aggregate_metric_notification') + ->where('aggregate_metric_spec_id = ?', $aggregateMetricSpecDao->getAggregateMetricSpecId()) + ->where('branch = ?', $branch); + $rows = $this->database->fetchAll($sql); + /** @var Zend_Db_Table_Row_Abstract $row */ + foreach ($rows as $row) { + $aggregateMetricNotificationDao = $this->initDao('AggregateMetricNotification', $row, $this->moduleName); + $value = floatval($aggregateMetricDao->getValue()); + $thresholdValue = floatval($aggregateMetricNotificationDao->getValue()); + /** @var bool $aboveThreshold */ + $aboveThreshold = false; + switch ($aggregateMetricNotificationDao->getComparison()) { + case '>': + $aboveThreshold = $value > $thresholdValue; + break; + case '<': + $aboveThreshold = $value < $thresholdValue; + break; + case '>=': + $aboveThreshold = $value >= $thresholdValue; + break; + case '<=': + $aboveThreshold = $value <= $thresholdValue; + break; + case '==': + $aboveThreshold = $value === $thresholdValue; + break; + case '!=': + $aboveThreshold = $value !== $thresholdValue; + break; + default: + $aboveThreshold = false; + } + + if ($aboveThreshold) { + $notifiedUsers = $this->getAllNotifiedUsers($aggregateMetricNotificationDao); + if ($notifiedUsers && count($notifiedUsers) > 0) { + /** @var Scheduler_JobModel $jobModel */ + $jobModel = MidasLoader::loadModel('Job', 'scheduler'); + /** @var userDao $userDao */ + foreach ($notifiedUsers as $userDao) { + /** @var Scheduler_JobDao $jobDao */ + $jobDao = MidasLoader::newDao('JobDao', 'scheduler'); + $jobDao->setTask('TASK_TRACKER_SEND_AGGREGATE_METRIC_NOTIFICATION'); + $jobDao->setPriority(MIDAS_EVENT_PRIORITY_HIGH); + $jobDao->setRunOnlyOnce(1); + $jobDao->setFireTime(date('Y-m-d H:i:s')); + $jobDao->setTimeInterval(0); + $jobDao->setStatus(SCHEDULER_JOB_STATUS_TORUN); + $jobDao->setCreatorId($userDao->getUserId()); + $jobDao->setParams(JsonComponent::encode(array( + 'aggregate_metric_notification_id' => $aggregateMetricNotificationDao->getAggregateMetricNotificationId(), + 'aggregate_metric_id' => $aggregateMetricDao->getAggregateMetricId(), + 'recipient_id' => $userDao->getUserId(), + ))); + $jobModel->save($jobDao); + $jobs[] = $jobDao; + } + } + } + } + + return $jobs; + } + + /** + * Delete the given aggregate metric notification, and any associated user + * notifications. + * + * @param Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao aggregateMetricNotification DAO + */ + public function delete($aggregateMetricNotificationDao) + { + if (is_null($aggregateMetricNotificationDao) || $aggregateMetricNotificationDao === false) { + return; + } + $this->database->getDB()->delete('tracker_user2aggregate_metric_notification', 'aggregate_metric_notification_id = '.$aggregateMetricNotificationDao->getAggregateMetricNotificationId()); + parent::delete($aggregateMetricNotificationDao); + } +} diff --git a/modules/tracker/models/pdo/AggregateMetricSpecModel.php b/modules/tracker/models/pdo/AggregateMetricSpecModel.php index 91877496f..be0e34d4a 100644 --- a/modules/tracker/models/pdo/AggregateMetricSpecModel.php +++ b/modules/tracker/models/pdo/AggregateMetricSpecModel.php @@ -23,172 +23,6 @@ /** AggregateMetricSpec model for the tracker module. */ class Tracker_AggregateMetricSpecModel extends Tracker_AggregateMetricSpecModelBase { - /** - * Create a user notification tied to the aggregate metric spec. - * - * @param Tracker_AggregateMetricSpecDao $aggregateMetricSpecDao aggregateMetricSpec DAO - * @param UserDao $userDao user DAO - * @return bool true if the notification could be created, false otherwise - */ - public function createUserNotification($aggregateMetricSpecDao, $userDao) - { - if (is_null($aggregateMetricSpecDao) || $aggregateMetricSpecDao === false) { - return false; - } - if (is_null($userDao) || $userDao === false) { - return false; - } - // Don't insert if it exists already. - $sql = $this->database->select()->setIntegrityCheck(false) - ->from('tracker_user2aggregate_metric_spec') - ->where('aggregate_metric_spec_id = ?', $aggregateMetricSpecDao->getAggregateMetricSpecId()) - ->where('user_id = ?', $userDao->getUserId()); - /** @var Zend_Db_Table_Row_Abstract $row */ - $row = $this->database->fetchRow($sql); - if (!is_null($row)) { - return true; - } else { - $data = array( - 'aggregate_metric_spec_id' => $aggregateMetricSpecDao->getAggregateMetricSpecId(), - 'user_id' => $userDao->getUserId(), - ); - $this->database->getdb()->insert('tracker_user2aggregate_metric_spec', $data); - - return true; - } - } - - /** - * Delete a user notification tied to the aggregate metric spec. - * - * @param Tracker_AggregateMetricSpecDao $aggregateMetricSpecDao aggregateMetricSpec DAO - * @param UserDao $userDao user DAO - * @return bool true if the user and aggregate metric spec are valid and a - * notification does not exist for this user and aggregate metric spec upon - * returning, false otherwise - */ - public function deleteUserNotification($aggregateMetricSpecDao, $userDao) - { - if (is_null($aggregateMetricSpecDao) || $aggregateMetricSpecDao === false) { - return false; - } - if (is_null($userDao) || $userDao === false) { - return false; - } - $this->database->getDB()->delete('tracker_user2aggregate_metric_spec', array( - 'aggregate_metric_spec_id = ?' => $aggregateMetricSpecDao->getAggregateMetricSpecId(), - 'user_id = ?' => $userDao->getUserId(), - )); - - return true; - } - - /** - * Return a list of User Daos for all users with notifications on this aggregate metric spec. - * - * @param Tracker_AggregateMetricSpecDao $aggregateMetricSpecDao aggregateMetricSpec DAO - * @return false|array of UserDao for all users with notification on the passed in $aggregateMetricSpecDao, - * or false if the passed in spec is invalid - */ - public function getAllNotifiedUsers($aggregateMetricSpecDao) - { - if (is_null($aggregateMetricSpecDao) || $aggregateMetricSpecDao === false) { - return false; - } - $sql = $this->database->select()->setIntegrityCheck(false) - ->from('tracker_user2aggregate_metric_spec', array('user_id')) - ->where('aggregate_metric_spec_id = ?', $aggregateMetricSpecDao->getAggregateMetricSpecId()); - $rows = $this->database->fetchAll($sql); - - $userDaos = array(); - /** @var userModel $userModel */ - $userModel = MidasLoader::loadModel('User'); - /** @var Zend_Db_Table_Row_Abstract $row */ - foreach ($rows as $row) { - $userDaos[] = $userModel->load($row['user_id']); - } - - return $userDaos; - } - - /** - * Return a list of Jobs scheduled to notify users that the passed aggregate metric is above - * the threshold defined in the passed aggregate metric spec. - * - * @param Tracker_AggregateMetricSpecDao $aggregateMetricSpecDao aggregateMetricSpec DAO - * @param Tracker_AggregateMetricDao $aggregateMetricDao aggregateMetric DAO - * @return false|array of Scheduler_JobDao for all users with a notification created, which will only - * be populated if the aggregate metric is above the threshold defined on the aggregate metric spec and - * there exist users to be notified on the aggregate metric spec, or false if the inputs are invalid. - */ - public function scheduleNotificationJobs($aggregateMetricSpecDao, $aggregateMetricDao) - { - if (is_null($aggregateMetricSpecDao) || $aggregateMetricSpecDao === false) { - return false; - } - if (is_null($aggregateMetricDao) || $aggregateMetricDao === false) { - return false; - } - - // if the value exists and the threshold exists, test it - $value = $aggregateMetricDao->getValue(); - $thresholdValue = $aggregateMetricSpecDao->getValue(); - /** @var bool $aboveThreshold */ - $aboveThreshold = false; - switch ($aggregateMetricSpecDao->getComparison()) { - case '>': - $aboveThreshold = $value > $thresholdValue; - break; - case '<': - $aboveThreshold = $value < $thresholdValue; - break; - case '>=': - $aboveThreshold = $value >= $thresholdValue; - break; - case '<=': - $aboveThreshold = $value <= $thresholdValue; - break; - case '==': - $aboveThreshold = $value === $thresholdValue; - break; - case '!=': - $aboveThreshold = $value !== $thresholdValue; - break; - default: - $aboveThreshold = false; - } - - $jobs = array(); - if ($aboveThreshold) { - $notifiedUsers = $this->getAllNotifiedUsers($aggregateMetricSpecDao); - if ($notifiedUsers && count($notifiedUsers) > 0) { - /** @var Scheduler_JobModel $jobModel */ - $jobModel = MidasLoader::loadModel('Job', 'scheduler'); - /** @var userDao $userDao */ - foreach ($notifiedUsers as $userDao) { - /** @var Scheduler_JobDao $jobDao */ - $jobDao = MidasLoader::newDao('JobDao', 'scheduler'); - $jobDao->setTask('TASK_TRACKER_SEND_AGGREGATE_METRIC_NOTIFICATION'); - $jobDao->setPriority(MIDAS_EVENT_PRIORITY_HIGH); - $jobDao->setRunOnlyOnce(1); - $jobDao->setFireTime(date('Y-m-d H:i:s')); - $jobDao->setTimeInterval(0); - $jobDao->setStatus(SCHEDULER_JOB_STATUS_TORUN); - $jobDao->setCreatorId($userDao->getUserId()); - $jobDao->setParams(JsonComponent::encode(array( - 'aggregate_metric_spec_id' => $aggregateMetricSpecDao->getAggregateMetricSpecId(), - 'aggregate_metric_id' => $aggregateMetricDao->getAggregateMetricId(), - 'recipient_id' => $userDao->getUserId(), - ))); - $jobModel->save($jobDao); - $jobs[] = $jobDao; - } - } - } - - return $jobs; - } - /** * Delete the given aggregate metric spec, any metrics calculated based on that spec, * and any associated notifications. @@ -200,10 +34,15 @@ public function delete($aggregateMetricSpecDao) if (is_null($aggregateMetricSpecDao) || $aggregateMetricSpecDao === false) { return; } - $this->database->getDB()->delete('tracker_user2aggregate_metric_spec', 'aggregate_metric_spec_id = '.$aggregateMetricSpecDao->getAggregateMetricSpecId()); + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', 'tracker'); + $aggregateMetricNotifications = $aggregateMetricNotificationModel->findBy('aggregate_metric_spec_id', $aggregateMetricSpecDao->getAggregateMetricSpecId()); + /** @var Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao */ + foreach ($aggregateMetricNotifications as $aggregateMetricNotificationDao) { + $aggregateMetricNotificationModel->delete($aggregateMetricNotificationDao); + } + // Delete all associated metrics. $this->database->getDB()->delete('tracker_aggregate_metric', 'aggregate_metric_spec_id = '.$aggregateMetricSpecDao->getAggregateMetricSpecId()); - $this->database->getDB()->delete('tracker_aggregate_metric_spec', 'aggregate_metric_spec_id = '.$aggregateMetricSpecDao->getAggregateMetricSpecId()); - parent::delete($aggregateMetricSpecDao); } } diff --git a/modules/tracker/models/pdo/ScalarModel.php b/modules/tracker/models/pdo/ScalarModel.php index 85b9e2653..2cd61c4a7 100644 --- a/modules/tracker/models/pdo/ScalarModel.php +++ b/modules/tracker/models/pdo/ScalarModel.php @@ -23,52 +23,6 @@ /** Scalar model for the tracker module. */ class Tracker_ScalarModel extends Tracker_ScalarModelBase { - /** - * Associate the given scalar and item. - * - * @param Tracker_ScalarDao $scalarDao scalar DAO - * @param ItemDao $itemDao item DAO - * @param string $label label - */ - public function associateItem($scalarDao, $itemDao, $label) - { - $data = array('scalar_id' => $scalarDao->getKey(), 'item_id' => $itemDao->getKey(), 'label' => $label); - $this->database->getDB()->insert('tracker_scalar2item', $data); - } - - /** - * Return the items associated with the given scalar. - * - * @param Tracker_ScalarDao $scalarDao scalar DAO - * @return array array of associative arrays with keys "item" and "label" - */ - public function getAssociatedItems($scalarDao) - { - $sql = $this->database->select()->setIntegrityCheck(false)->from('tracker_scalar2item')->where( - 'scalar_id = ?', - $scalarDao->getKey() - ); - $rows = $this->database->fetchAll($sql); - $results = array(); - - /** @var ItemModel $itemModel */ - $itemModel = MidasLoader::loadModel('Item'); - - /** @var Zend_Db_Table_Row_Abstract $row */ - foreach ($rows as $row) { - $itemDao = $itemModel->load($row['item_id']); - $results[] = array('label' => $row['label'], 'item' => $itemDao); - } - usort( - $results, - function ($a, $b) { - return strcmp($a['label'], $b['label']); - } - ); - - return $results; - } - /** * Return any other scalars from the same submission as the given scalar. * @@ -77,14 +31,10 @@ function ($a, $b) { */ public function getOtherScalarsFromSubmission($scalarDao) { - $sql = $this->database->select()->from('tracker_scalar')->join( - 'tracker_trend', - 'tracker_scalar.trend_id = tracker_trend.trend_id', - array() - )->where('tracker_scalar.submit_time = ?', $scalarDao->getSubmitTime())->where( - 'tracker_scalar.user_id = ?', - $scalarDao->getUserId() - )->where('tracker_trend.producer_id = ?', $scalarDao->getTrend()->getProducerId()); + $sql = $this->database->select()->from(array('s' => 'tracker_scalar'))->join( + array('u' => 'tracker_submission'), + 'tracker_scalar.submission_id = tracker_submission.submission_id' + )->where('s.submission_id = ?', $scalarDao->getSubmissionId()); $rows = $this->database->fetchAll($sql); $scalarDaos = array(); @@ -96,32 +46,6 @@ public function getOtherScalarsFromSubmission($scalarDao) return $scalarDaos; } - /** - * Return any other values from the same submission as the given scalar. - * - * @param Tracker_ScalarDao $scalarDao scalar DAO - * @return array associative array with keys equal to the metric names - */ - public function getOtherValuesFromSubmission($scalarDao) - { - $sql = $this->database->select()->setIntegrityCheck(false)->from(array('s' => 'tracker_scalar'))->join( - array('t' => 'tracker_trend'), - 's.trend_id = t.trend_id' - )->where('s.submit_time = ?', $scalarDao->getSubmitTime())->where( - 's.user_id = ?', - $scalarDao->getUserId() - )->where('t.producer_id = ?', $scalarDao->getTrend()->getProducerId())->order('metric_name ASC'); - $rows = $this->database->fetchAll($sql); - $scalarDaos = array(); - - /** @var Zend_Db_Table_Row_Abstract $row */ - foreach ($rows as $row) { - $scalarDaos[$row['metric_name']] = array('value' => number_format((float) $row['value'], 4, '.', ''), 'unit' => $row['unit']); - } - - return $scalarDaos; - } - /** * Delete the given scalar and any associations to items. * @@ -129,9 +53,6 @@ public function getOtherValuesFromSubmission($scalarDao) */ public function delete($scalarDao) { - $this->database->getDB()->delete('tracker_scalar2item', 'scalar_id = '.$scalarDao->getKey()); - $this->database->getDB()->delete('tracker_param', 'scalar_id = '.$scalarDao->getKey()); - parent::delete($scalarDao); } @@ -145,12 +66,13 @@ public function delete($scalarDao) */ public function getByTrendAndTimestamp($trendId, $submitTime, $userId = null) { - $sql = $this->database->select()->setIntegrityCheck(false)->where('trend_id = ?', $trendId)->where( - 'submit_time = ?', - $submitTime - ); + $sql = $this->database->select()->setIntegrityCheck(false)->from(array('s' => 'tracker_scalar'))->join( + array('u' => 'tracker_submission'), + 's.submission_id=u.submission_id' + )->where('s.trend_id = ?', $trendId + )->where('u.submit_time = ?', $submitTime); if (!is_null($userId)) { - $sql->where('user_id = ?', $userId); + $sql->where('u.user_id = ?', $userId); } return $this->initDao('Scalar', $this->database->fetchRow($sql), $this->moduleName); diff --git a/modules/tracker/models/pdo/SubmissionModel.php b/modules/tracker/models/pdo/SubmissionModel.php index 07b8ea759..acdae2c10 100644 --- a/modules/tracker/models/pdo/SubmissionModel.php +++ b/modules/tracker/models/pdo/SubmissionModel.php @@ -27,15 +27,72 @@ class Tracker_SubmissionModel extends Tracker_SubmissionModelBase { const SEC_IN_DAY = 86400; + /** + * Associate the given submission and item. + * + * @param Tracker_SubmissionDao $submissionDao submission DAO + * @param ItemDao $itemDao item DAO + * @param string $label label + * @param Tracker_TrendgroupDao $trendgroupDao trendgroup DAO + */ + public function associateItem($submissionDao, $itemDao, $label, $trendgroupDao) + { + $data = array( + 'submission_id' => $submissionDao->getKey(), + 'item_id' => $itemDao->getKey(), + 'label' => $label, + 'trendgroup_id' => $trendgroupDao->getKey(), + ); + $this->database->getDB()->insert('tracker_submission2item', $data); + } + + /** + * Return the items associated with the given submission. + * + * @param Tracker_SubmissionDao $submissionDao submission DAO + * @param Tracker_TrendgroupDao $trendgroupDao trendgroup DAO + * @return array array of associative arrays with keys "item" and "label" + */ + public function getAssociatedItems($submissionDao, $trendgroupDao) + { + $sql = $this->database->select()->setIntegrityCheck(false)->from('tracker_submission2item')->where( + 'submission_id = ?', + $submissionDao->getKey() + )->where( + 'trendgroup_id = ?', + $trendgroupDao->getKey() + ); + $rows = $this->database->fetchAll($sql); + $results = array(); + + /** @var ItemModel $itemModel */ + $itemModel = MidasLoader::loadModel('Item'); + + /** @var Zend_Db_Table_Row_Abstract $row */ + foreach ($rows as $row) { + $itemDao = $itemModel->load($row['item_id']); + $results[] = array('label' => $row['label'], 'item' => $itemDao); + } + usort( + $results, + function ($a, $b) { + return strcmp($a['label'], $b['label']); + } + ); + + return $results; + } + /** * Create a submission. * * @param Tracker_ProducerDao $producerDao the producer to which the submission was submitted * @param string $uuid the uuid of the submission * @param string $name the name of the submission (defaults to '') - * @return void + * @param array $params the parameters used to generate the submission (defaults to null) + * @return Tracker_SubmissionDao */ - public function createSubmission($producerDao, $uuid, $name = '') + public function createSubmission($producerDao, $uuid, $name = '', $params = null) { $data = array( 'producer_id' => $producerDao->getKey(), @@ -43,6 +100,20 @@ public function createSubmission($producerDao, $uuid, $name = '') 'name' => $name, ); $this->database->getDB()->insert('tracker_submission', $data); + $submissionDao = $this->getSubmission($uuid); + if (!empty($params) && is_array($params)) { + $paramModel = MidasLoader::loadModel('Param', $this->moduleName); + foreach ($params as $paramName => $paramValue) { + /** @var Tracker_ParamDao $paramDao */ + $paramDao = MidasLoader::newDao('ParamDao', $this->moduleName); + $paramDao->setSubmissionId($submissionDao->getKey()); + $paramDao->setParamName($paramName); + $paramDao->setParamValue($paramValue); + $paramModel->save($paramDao); + } + } + + return $submissionDao; } /** @@ -50,20 +121,22 @@ public function createSubmission($producerDao, $uuid, $name = '') * * @param Tracker_SubmissionDao $submissionDao submission DAO * @param bool $key whether to only retrieve scalars of key trends + * @param bool|false|Tracker_TrendgroupDao $trendGroup dao of trend group to limit scalars * @return array scalar DAOs + * @throws Zend_Exception */ - public function getScalars($submissionDao, $key = false) + public function getScalars($submissionDao, $key = false, $trendGroup = false) { + $sql = $this->database->select()->setIntegrityCheck(false)->from('tracker_scalar')->join( + 'tracker_trend', + 'tracker_scalar.trend_id = tracker_trend.trend_id', + array() + )->where('submission_id = ?', $submissionDao->getKey()); if ($key) { - $sql = $this->database->select()->setIntegrityCheck(false)->from('tracker_scalar')->join( - 'tracker_trend', - 'tracker_scalar.trend_id = tracker_trend.trend_id', - array() - )->where('submission_id = ?', $submissionDao->getKey() - )->where('key_metric = ?', 1); - } else { - $sql = $this->database->select()->setIntegrityCheck(false)->from('tracker_scalar') - ->where('submission_id = ?', $submissionDao->getKey()); + $sql = $sql->where('key_metric = ?', 1); + } + if ($trendGroup) { + $sql = $sql->where('trendgroup_id = ?', $trendGroup->getKey()); } $scalarDaos = array(); @@ -77,6 +150,30 @@ public function getScalars($submissionDao, $key = false) return $scalarDaos; } + /** + * Return the values (trend name, value, and unit in an array) from a given submission. + * + * @param Tracker_SubmissionDao $submissionDao submission DAO + * @return array associative array with keys equal to the metric names + */ + public function getValuesFromSubmission($submissionDao) + { + $sql = $this->database->select()->setIntegrityCheck(false)->from(array('s' => 'tracker_scalar'))->join( + array('t' => 'tracker_trend'), + 's.trend_id = t.trend_id' + )->where('s.submission_id = ?', $submissionDao->getSubmissionId() + )->order('metric_name ASC'); + + $rows = $this->database->fetchAll($sql); + $scalarDaos = array(); + /** @var Zend_Db_Table_Row_Abstract $row */ + foreach ($rows as $row) { + $scalarDaos[$row['metric_name']] = array('value' => number_format((float) $row['value'], 4, '.', ''), 'unit' => $row['unit']); + } + + return $scalarDaos; + } + /** * Get submissions associated with a given producer. * @@ -174,15 +271,11 @@ public function getLatestSubmissionByProducerDateAndBranch($producerDao, $date = $dayBeforeQueryTime = date('Y-m-d H:i:s', strtotime($queryTime) - self::SEC_IN_DAY); $sql = $this->database->select()->setIntegrityCheck(false) ->from('tracker_submission') - ->join( - 'tracker_scalar', - 'tracker_submission.submission_id = tracker_scalar.submission_id', - array()) - ->where('tracker_submission.submit_time <= ?', $queryTime); + ->where('submit_time <= ?', $queryTime); if ($onlyOneDay) { - $sql = $sql->where('tracker_submission.submit_time > ?', $dayBeforeQueryTime); + $sql = $sql->where('submit_time > ?', $dayBeforeQueryTime); } - $sql = $sql->where('tracker_submission.producer_id = ?', $producerDao->getKey()) + $sql = $sql->where('producer_id = ?', $producerDao->getKey()) ->where('branch = ?', $branch) ->order('submit_time DESC') ->limit(1); @@ -223,4 +316,38 @@ public function getTrends($submissionDao, $key = true) return $trendDaos; } + + /** + * Return all distinct branch names from submissions. + * + * @return array branch names + */ + public function getDistinctBranches() + { + $sql = $this->database->select()->setIntegrityCheck(false)->from( + array('s' => 'tracker_submission'), + 'branch' + )->distinct(); + $rows = $this->database->fetchAll($sql); + $branches = array(); + /** @var Zend_Db_Table_Row_Abstract $row */ + foreach ($rows as $row) { + $branches[] = $row['branch']; + } + + return $branches; + } + + /** + * Delete a given submission. + * + * @param Tracker_SubmissionDao $submissionDao + */ + public function delete($submissionDao) + { + $this->database->getDB()->delete('tracker_submission2item', 'submission_id = '.$submissionDao->getKey()); + $this->database->getDB()->delete('tracker_param', 'submission_id = '.$submissionDao->getKey()); + + parent::delete($submissionDao); + } } diff --git a/modules/tracker/models/pdo/TrendModel.php b/modules/tracker/models/pdo/TrendModel.php index ef8b252c6..782dc874c 100644 --- a/modules/tracker/models/pdo/TrendModel.php +++ b/modules/tracker/models/pdo/TrendModel.php @@ -24,43 +24,40 @@ class Tracker_TrendModel extends Tracker_TrendModelBase { /** - * Return the trend DAO that matches the given the producer id, metric name, associated items, and unit. + * Return the trend DAO that matches the given the producer id, metric name, and associated items. * * @param int $producerId producer id * @param string $metricName metric name * @param null|int $configItemId configuration item id * @param null|int $testDatasetId test dataset item id * @param null|int $truthDatasetId truth dataset item id - * @param false|string $unit (Optional) scalar value unit, defaults to false * @return false|Tracker_TrendDao trend DAO or false if none exists */ - public function getMatch($producerId, $metricName, $configItemId, $testDatasetId, $truthDatasetId, $unit = false) + public function getMatch($producerId, $metricName, $configItemId, $testDatasetId, $truthDatasetId) { - $sql = $this->database->select()->setIntegrityCheck(false)->where('producer_id = ?', $producerId)->where( - 'metric_name = ?', + $sql = $this->database->select()->setIntegrityCheck(false)->from(array('t' => 'tracker_trend') + )->join(array('g' => 'tracker_trendgroup'), 't.trendgroup_id = g.trendgroup_id' + )->where('g.producer_id = ?', $producerId)->where( + 't.metric_name = ?', $metricName ); if (is_null($configItemId)) { - $sql->where('config_item_id IS NULL'); + $sql->where('g.config_item_id IS NULL'); } else { - $sql->where('config_item_id = ?', $configItemId); + $sql->where('g.config_item_id = ?', $configItemId); } if (is_null($truthDatasetId)) { - $sql->where('truth_dataset_id IS NULL'); + $sql->where('g.truth_dataset_id IS NULL'); } else { - $sql->where('truth_dataset_id = ?', $truthDatasetId); + $sql->where('g.truth_dataset_id = ?', $truthDatasetId); } if (is_null($testDatasetId)) { - $sql->where('test_dataset_id IS NULL'); + $sql->where('g.test_dataset_id IS NULL'); } else { - $sql->where('test_dataset_id = ?', $testDatasetId); - } - - if ($unit !== false) { - $sql->where('unit = ?', $unit); + $sql->where('g.test_dataset_id = ?', $testDatasetId); } return $this->initDao('Trend', $this->database->fetchRow($sql), $this->moduleName); @@ -78,24 +75,26 @@ public function getMatch($producerId, $metricName, $configItemId, $testDatasetId */ public function getScalars($trendDao, $startDate = null, $endDate = null, $userId = null, $branch = null) { - $sql = $this->database->select()->setIntegrityCheck(false)->from('tracker_scalar')->where( + $sql = $this->database->select()->setIntegrityCheck(false)->from(array('s' => 'tracker_scalar') + )->join(array('u' => 'tracker_submission'), 's.submission_id = u.submission_id' + )->where( 'trend_id = ?', $trendDao->getKey() - )->order(array('submit_time ASC')); + )->order(array('u.submit_time ASC')); if (!is_null($startDate)) { - $sql->where('submit_time >= ?', $startDate); + $sql->where('u.submit_time >= ?', $startDate); } if (!is_null($endDate)) { - $sql->where('submit_time <= ?', $endDate); + $sql->where('u.submit_time <= ?', $endDate); } if (!is_null($branch)) { if (is_array($branch)) { - $sql->where('branch IN (?)', $branch); + $sql->where('u.branch IN (?)', $branch); } else { - $sql->where('branch = ?', $branch); + $sql->where('u.branch = ?', $branch); } } @@ -111,24 +110,23 @@ public function getScalars($trendDao, $startDate = null, $endDate = null, $userI } /** - * Return all trends corresponding to the given producer. They will be grouped by distinct - * config/test/truth dataset combinations. + * Return all trends corresponding to the given producer. They will be grouped by their trend + * group and returned along with the test, truth, and config item DAOs. * * @param Tracker_ProducerDao $producerDao producer DAO * @param bool $onlyKey whether to return only key trends * @return array array of associative arrays with keys "configItem", "testDataset", "truthDataset", and "trends" */ - public function getTrendsGroupByDatasets($producerDao, $onlyKey = false) + public function getTrendsByGroup($producerDao, $onlyKey = false) { - $sql = $this->database->select()->setIntegrityCheck(false)->from( - $this->_name, - array('config_item_id', 'test_dataset_id', 'truth_dataset_id') - )->where('producer_id = ?', $producerDao->getKey())->distinct(); + $sql = $this->database->select()->setIntegrityCheck(false) + ->from('tracker_trendgroup') + ->where('producer_id = ?', $producerDao->getKey()); + $rows = $this->database->fetchAll($sql); /** @var ItemModel $itemModel */ $itemModel = MidasLoader::loadModel('Item'); $results = array(); - $rows = $this->database->fetchAll($sql); /** @var Zend_Db_Table_Row_Abstract $row */ foreach ($rows as $row) { @@ -141,10 +139,7 @@ public function getTrendsGroupByDatasets($producerDao, $onlyKey = false) 'truthDataset' => $truthDatasetItemDao, ); $queryParams = array( - 'producer_id' => $producerDao->getKey(), - 'config_item_id' => $row['config_item_id'], - 'test_dataset_id' => $row['test_dataset_id'], - 'truth_dataset_id' => $row['truth_dataset_id'], + 't.trendgroup_id' => $row['trendgroup_id'], ); if ($onlyKey !== false) { $queryParams['key_metric'] = '1'; @@ -164,7 +159,7 @@ public function getTrendsGroupByDatasets($producerDao, $onlyKey = false) */ public function getAllByParams($params) { - $sql = $this->database->select()->setIntegrityCheck(false); + $sql = $this->database->select()->from(array('t' => 'tracker_trend'))->join(array('g' => 'tracker_trendgroup'), 't.trendgroup_id=g.trendgroup_id')->setIntegrityCheck(false); /** * @var string $column @@ -189,39 +184,4 @@ public function getAllByParams($params) return $trendDaos; } - - /** - * Return all distinct branch names producing scalars, tied to a specific - * producer, for trends that are key_metrics, and matching a trend metric_name. - * - * @param int $producerId producer id - * @param string $metricName trend metric_name - * @return array branch names - */ - public function getDistinctBranchesForMetricName($producerId, $metricName) - { - $sql = $this->database->select()->setIntegrityCheck(false)->from( - array('tracker_scalar'), - 'branch' - ) - ->distinct() - ->join( - 'tracker_trend', - 'tracker_scalar.trend_id = tracker_trend.trend_id', - array() - ) - ->where('tracker_trend.producer_id = ?', $producerId) - ->where('tracker_trend.key_metric = ?', 1) - ->where('tracker_trend.metric_name = ?', $metricName); - - $rows = $this->database->fetchAll($sql); - $branches = array(); - - /** @var Zend_Db_Table_Row_Abstract $row */ - foreach ($rows as $row) { - $branches[] = $row['branch']; - } - - return $branches; - } } diff --git a/modules/tracker/models/pdo/TrendgroupModel.php b/modules/tracker/models/pdo/TrendgroupModel.php new file mode 100644 index 000000000..544b5be7e --- /dev/null +++ b/modules/tracker/models/pdo/TrendgroupModel.php @@ -0,0 +1,84 @@ +database->select()->setIntegrityCheck(false + )->where('producer_id = ?', $producerId); + + if (is_null($configItemId)) { + $sql->where('config_item_id IS NULL'); + } else { + $sql->where('config_item_id = ?', $configItemId); + } + + if (is_null($truthDatasetId)) { + $sql->where('truth_dataset_id IS NULL'); + } else { + $sql->where('truth_dataset_id = ?', $truthDatasetId); + } + + if (is_null($testDatasetId)) { + $sql->where('test_dataset_id IS NULL'); + } else { + $sql->where('test_dataset_id = ?', $testDatasetId); + } + + /** @var Tracker_TrendGroupDao $trendGroupDao */ + $trendgroupDao = $this->initDao('Trendgroup', $this->database->fetchRow($sql), $this->moduleName); + + if ($trendgroupDao === false) { + $trendgroupDao = MidasLoader::newDao('TrendgroupDao', $this->moduleName); + + $trendgroupDao->setProducerId($producerId); + + if (!is_null($configItemId)) { + $trendgroupDao->setConfigItemId($configItemId); + } + + if (!is_null($testDatasetId)) { + $trendgroupDao->setTestDatasetId($testDatasetId); + } + + if (!is_null($truthDatasetId)) { + $trendgroupDao->setTruthDatasetId($truthDatasetId); + } + + $this->save($trendgroupDao); + } + + return $trendgroupDao; + } +} diff --git a/modules/tracker/public/css/producer/producer.aggregatemetric.css b/modules/tracker/public/css/producer/producer.aggregatemetric.css index 4f83149fd..b1067d425 100644 --- a/modules/tracker/public/css/producer/producer.aggregatemetric.css +++ b/modules/tracker/public/css/producer/producer.aggregatemetric.css @@ -1 +1 @@ -a.aggregateMetricSpecAction{color:#56758b}a.aggregateMetricSpecAction:hover{background-color:#e5e5e5;cursor:pointer}a.alertedUsersAction{color:#56758b}a.alertedUsersAction:hover{background-color:#e5e5e5;cursor:pointer}div#addAggregateMetricSpec{margin-top:10px}div#aggregateMetricSpecList{margin-top:10px}div.aggregateMetricSpecCreate{border-top:2px solid darkblue !important}div.aggregateMetricSpecEdit{border-top:2px solid darkblue !important}div#aggregateMetricSpecEditWarning{padding-top:10px;padding-bottom:10px;color:orange}div#aggregateMetricUserAlerts{border-top:2px solid darkblue;color:#555;font-size:13px;margin-top:15px;margin-bottom:10px;padding-top:10px;text-align:center}div#aggregateMetricUserAlerts div#aggregateMetricUserAlertsThreshold{margin-top:15px;margin-bottom:10px}div#aggregateMetricUserAlerts div#aggregateMetricUserAlertsThreshold table#aggregateMetricUserAlertsThresholdDefinition{margin-top:10px}div#aggregateMetricUserAlerts div#aggregateMetricUserAlertsThreshold table#aggregateMetricUserAlertsThresholdDefinition td:first-of-type{text-align:left}div#aggregateMetricUserAlerts textarea#aggregateMetricUserAlertsSpec{margin-top:10px;width:100%}div#aggregateMetricUserAlerts div#addAggregateMetricSpecAlertUser{margin-top:15px;text-align:center}div#aggregateMetricUserAlerts div.alertUserSearch{margin-top:10px}div#aggregateMetricUserAlerts div.alertUserSearch input{width:100%}div.aggregateMetricSectionTitle{border-top:1px solid #d7d7d7;color:#555;font-size:13px;margin-top:15px;margin-bottom:10px;padding-top:10px;text-align:center}div.resultingMetricText{color:#555;font-size:12px;margin-top:10px;text-align:center}div#aggregateMetricSpecUserAlertsSaveState{margin-top:20px}div#aggregateMetricSpecUserAlertsSaveState input{background:#f6f9fe;border:1px solid #808080;color:#2e6e9e;cursor:pointer;float:right;margin-left:10px}div#aggregateMetricSpecSaveState{margin-top:20px}div#aggregateMetricSpecSaveState input{background:#f6f9fe;border:1px solid #808080;color:#2e6e9e;cursor:pointer;float:right;margin-left:10px}div#aggregateMetricSpecSaveState input:disabled{color:#c0c0c0;cursor:not-allowed}label#aggregateMetricSpecValidationError{color:crimson}img#aggregateMetricSpecSaveLoading{float:left;margin-right:15px}img#aggregateMetricSpecDeleteLoading{float:right;margin-right:40px}img#aggregateMetricSpecAlertsLoading{float:left}table#aggregateMetricSpecAlertedUsers{table-layout:fixed;border:2px solid #ddd;width:100%}table#aggregateMetricSpecAlertedUsers th{border-bottom:solid 1px black;text-align:center}table#aggregateMetricSpecAlertedUsers th:first-of-type{width:70%;border-right:dotted 1px black}table#aggregateMetricSpecAlertedUsers tr.even{background-color:#f4f4f4}table#aggregateMetricSpecAlertedUsers td.userName{border-right:dotted 1px black;text-align:left}table#aggregateMetricSpecAlertedUsers tr.activeRow{border:2px solid darkblue;background-color:#c0d1fe}table#aggregateMetricSpecListTable{table-layout:fixed;border:2px solid #ddd;width:100%}table#aggregateMetricSpecListTable th{border-bottom:solid 1px black;text-align:center}table#aggregateMetricSpecListTable th:first-of-type{width:70%;border-right:dotted 1px black}table#aggregateMetricSpecListTable td.specName{border-right:dotted 1px black}table#aggregateMetricSpecListTable tr.even{background-color:#f4f4f4}table#aggregateMetricSpecListTable tr.activeRow{border:2px solid darkblue;background-color:#c0d1fe}table#aggregateMetricSpecListTable span.actionsList{display:flex;justify-content:space-around}table#aggregateMetricSpecListTable span.actionsList a:first-of-type{padding-left:5px} +div#aggregateMetricSpecManage table{width:100%}div#aggregateMetricSpecManage table.actionTable{table-layout:fixed;border:2px solid #ddd;margin-top:15px;margin-bottom:15px}div#aggregateMetricSpecManage table.actionTable tr.activeRow{border:2px solid darkblue;background-color:#c0d1fe !important}div#aggregateMetricSpecManage table.actionTable tr.even{background-color:#f4f4f4}div#aggregateMetricSpecManage table.actionTable th{border-bottom:solid 1px black}div#aggregateMetricSpecManage table.actionTable th:last-of-type{text-align:center;border-left:dotted 1px black;width:30%}div#aggregateMetricSpecManage table.actionTable td:last-of-type{border-left:dotted 1px black}div#aggregateMetricSpecManage table.actionTable span.actionsList{display:flex;justify-content:space-around}div#aggregateMetricSpecManage table.actionTable span.actionsList a:first-of-type{padding-left:5px}div#aggregateMetricSpecManage table.fieldTable input{width:100%}div#aggregateMetricSpecManage table.fieldTable select{width:100%}div#aggregateMetricSpecManage a.actionLink{color:#56758b}div#aggregateMetricSpecManage a.actionLink:hover{background-color:#e5e5e5;cursor:pointer}div#aggregateMetricSpecManage label.validationError{color:crimson}div#aggregateMetricSpecManage div.subsectionTitle{border-top:2px solid darkblue;margin-top:15px;margin-bottom:15px;padding-top:10px;color:#555;font-size:13px;text-align:center;font-weight:bold}div#aggregateMetricSpecManage div.subsubsectionTitle{color:#555;font-size:12px;margin-top:10px;margin-bottom:10px;text-align:center}div#aggregateMetricSpecManage div.saveState{margin-top:15px}div#aggregateMetricSpecManage div.saveState input{background:#f6f9fe;border:1px solid #808080;color:#2e6e9e;cursor:pointer;float:right;margin-left:10px}div#aggregateMetricSpecManage div.saveState input:disabled{color:#c0c0c0;cursor:not-allowed}div#aggregateMetricSpecManage div#aggregateMetricSpecEditWarning{padding-top:10px;padding-bottom:10px;color:orange}div#aggregateMetricSpecManage img.loadingImg{float:left}div#aggregateMetricSpecManage img.loadingImg#aggregateMetricSpecDeleteLoading{float:right;margin-right:40px}div#aggregateMetricSpecManage textarea#aggregateMetricUserAlertsSpec{margin-top:10px;width:100%}div#aggregateMetricSpecManage input#addAlertUserSearch{width:100%} diff --git a/modules/tracker/public/js/producer/producer.aggregateMetric.js b/modules/tracker/public/js/producer/producer.aggregateMetric.js index f24f959f8..79b7e28e1 100644 --- a/modules/tracker/public/js/producer/producer.aggregateMetric.js +++ b/modules/tracker/public/js/producer/producer.aggregateMetric.js @@ -8,27 +8,30 @@ var midas = midas || {}; $(document).ready(function () { 'use strict'; + var activeNotification = null; + var activeSpecNotifications = {}; + //:~ Server API interfaces /** - * Interface to server side AggregateMetricSpec REST API. + * Interface to server side midas REST API. * @param method The HTTP method {'POST'|'PUT'|'DELETE'|'GET'} - * @param aggregateMetricSpecId (Required for all except POST) - * @param args an object containing key value pairs for the AggregateMetricSpec object for PUT calls (Optional except for PUT) + * @param resourceId (Required for all except POST) + * @param args an object containing key value pairs for the resource object for PUT calls (Optional except for PUT) * @param sCb success callback, passed the return value (Optional) * @param eCb error callback, passed the return value (Optional) * @param cCb complete callback, passed the return value (Optional) */ - function aggregatemetricspecRest(method, aggregateMetricSpecId, args, sCb, eCb, cCb) { - var url = json.global.webroot + '/rest/tracker/aggregatemetricspec'; - if (aggregateMetricSpecId) { - url += '/' + aggregateMetricSpecId; + function midasRest(httpMethod, path, resourceId, args, sCb, eCb, cCb) { + var url = json.global.webroot + path; + if (resourceId) { + url += '/' + resourceId; } url += '?useSession=true'; var restCall = { url: url, - type: method, + type: httpMethod, dataType: 'json', success: function (retVal) { if (sCb) { sCb(retVal); } @@ -51,6 +54,34 @@ $(document).ready(function () { $.ajax(restCall); } + /** + * Interface to server side AggregateMetricSpec REST API. + * @param method The HTTP method {'POST'|'PUT'|'DELETE'|'GET'} + * @param aggregateMetricSpecId (Required for all except POST) + * @param args an object containing key value pairs for the AggregateMetricSpec object for PUT calls (Optional except for PUT) + * @param sCb success callback, passed the return value (Optional) + * @param eCb error callback, passed the return value (Optional) + * @param cCb complete callback, passed the return value (Optional) + */ + function aggregatemetricspecRest(method, aggregateMetricSpecId, args, sCb, eCb, cCb) { + var path = '/rest/tracker/aggregatemetricspec'; + midasRest(method, path, aggregateMetricSpecId, args, sCb, eCb, cCb); + } + + /** + * Interface to server side AggregateMetricNotification REST API. + * @param method The HTTP method {'POST'|'PUT'|'DELETE'|'GET'} + * @param aggregateMetricNotificationId (Required for all except POST) + * @param args an object containing key value pairs for the AggregateMetricNotification object for PUT calls (Optional except for PUT) + * @param sCb success callback, passed the return value (Optional) + * @param eCb error callback, passed the return value (Optional) + * @param cCb complete callback, passed the return value (Optional) + */ + function aggregatemetricnotificationRest(method, aggregateMetricNotificationId, args, sCb, eCb, cCb) { + var path = '/rest/tracker/aggregatemetricnotification'; + midasRest(method, path, aggregateMetricNotificationId, args, sCb, eCb, cCb); + } + /** * Additional wrapper around ajaxWebApi.ajax to provide some defaults. * @param string jsonMethod the midas json method @@ -150,8 +181,8 @@ $(document).ready(function () { function addToSpecTable(aggregateMetricSpec) { function createActionLink(qtip, actionClass, imgPath, label) { - var actionLink = ' '; - actionLink += ' '+label+''; + var actionLink = ' '; + actionLink += ' '+label+''; return actionLink; } @@ -226,6 +257,7 @@ $(document).ready(function () { /** Handler for Alerts button, show the panel to edit the alerted users. */ $('#aggregateMetricSpecListTable').on('click', 'a.editAggregateMetricSpecNotificationUsers', function() { activateRow($(this)); + unhighlightActiveAlertRow(); var amsName = $('td:first', $(this).closest('tr')).text(); $('#aggregateMetricUserAlerts').show(); var aggregateMetricSpecId = $(this).data('aggregate_metric_spec_id'); @@ -235,25 +267,25 @@ $(document).ready(function () { $('#aggregateMetricSpecAlertComparison').val(''); $('#aggregateMetricUserAlertsSpec').val(''); $('#aggregateMetricSpecAlertedUsers').find('tr:gt(0)').remove(); - $('#aggregateMetricSpecAlertsLoading').show(); + $('#aggregateMetricNotificationsTable').find('tr:gt(0)').remove(); + $('#aggregateMetricNotificationRemoveLoading').show(); $('#addAlertUserSearch').val('Start typing a name or email address...'); $('#addAlertUserSearchValue').val('init'); var successCallback = function (aggregateMetricSpec) { $('#aggregateMetricUserAlertsSpecName').text(aggregateMetricSpec.name); - $('#aggregateMetricUserAlertsBranch').text(aggregateMetricSpec.branch); - $('#aggregateMetricSpecAlertValue').val(aggregateMetricSpec.value); - $('#aggregateMetricSpecAlertComparison').val(aggregateMetricSpec.comparison); $('#aggregateMetricUserAlertsSpec').val(aggregateMetricSpec.spec); - var jsonMethod = 'midas.tracker.aggregatemetricspecnotifiedusers.list'; + var jsonMethod = 'midas.tracker.aggregatemetricspecnotifications.list'; var args = 'aggregateMetricSpecId=' + aggregateMetricSpecId; callAjaxWebApi(jsonMethod, 'GET', args, function (retVal) { - for (var userInd = 0; userInd < retVal.data.length; userInd++) { - var user = retVal.data[userInd]; - addToAlertedUsersTable(user.firstname + ' ' + user.lastname, user.user_id); + activeSpecNotifications = {}; + for (var notifInd = 0; notifInd < retVal.data.length; notifInd++) { + var notification = retVal.data[notifInd]; + addToNotificationTable(notification.notification); + activeSpecNotifications[notification.notification.aggregate_metric_notification_id] = notification; } - addClassesToTableRows('aggregateMetricSpecAlertedUsers'); - $('#aggregateMetricSpecAlertsLoading').hide(); + addClassesToTableRows('aggregateMetricNotificationsTable'); + $('#aggregateMetricNotificationRemoveLoading').hide(); }); }; aggregatemetricspecRest('GET', aggregateMetricSpecId, null, successCallback); @@ -277,7 +309,6 @@ $(document).ready(function () { var requiredFields = [ {'value': specValues.aggregateMetricSpec.name, 'name': 'Name'}, {'value': specValues.specInputs.metricName, 'name': 'Metric name'}, - {'value': specValues.aggregateMetricSpec.branch, 'name': 'Branch'}, {'value': specValues.specInputs.aggregateMetric, 'name': 'Aggregate metric'}, {'value': specValues.specInputs.param, 'name': 'Param (percentile)'} ]; @@ -296,19 +327,6 @@ $(document).ready(function () { $('div#aggregateMetricSpecSaveState input').prop('disabled', false); return; } - // Comparison and valid must be empty or not together. - var comparisonEmpty = (!specValues.aggregateMetricSpec.comparison || specValues.aggregateMetricSpec.comparison === ''); - var valueEmpty = (!specValues.aggregateMetricSpec.value || specValues.aggregateMetricSpec.value === ''); - if (comparisonEmpty !== valueEmpty) { - $('#aggregateMetricSpecValidationError').text('Comparison and value must be set together'); - $('div#aggregateMetricSpecSaveState input').prop('disabled', false); - return; - } else if (!valueEmpty && !$.isNumeric(specValues.aggregateMetricSpec.value)) { - // The case where comparison and value are provided. - $('#aggregateMetricSpecValidationError').text('Value must be numeric'); - $('div#aggregateMetricSpecSaveState input').prop('disabled', false); - return; - } // Save the AMS on the server. $('#aggregateMetricSpecSaveLoading').show(); @@ -332,8 +350,6 @@ $(document).ready(function () { $('#aggregateMetricSpecValidationError').text(''); $('#aggregateMetricSpecSpec').val(''); $('#aggregateMetricSpecMetricName option:disabled').attr('selected', 'selected'); - $('#aggregateMetricSpecComparison option:disabled').attr('selected', 'selected'); - $('#aggregateMetricSpecBranch').val('master'); } /** Update display of disabled composite spec input from individual elements. */ @@ -374,10 +390,7 @@ $(document).ready(function () { 'producer_id': $('#producerId').val(), 'name': $('#aggregateMetricSpecName').val(), 'description': $('#aggregateMetricSpecDescription').val(), - 'branch': $('#aggregateMetricSpecBranch').val(), 'spec': $('#aggregateMetricSpecSpec').val(), - 'value': $('#aggregateMetricSpecValue').val(), - 'comparison': $('#aggregateMetricSpecComparison').val() }, 'specInputs': { 'metricName': $('#aggregateMetricSpecMetricName').val(), @@ -391,7 +404,7 @@ $(document).ready(function () { /** * Populate the input elements with the values from the passed in aggregateMetricSpec, * including some validation in case the passed in spec was created out of data that is - * no longer valid, e.g. a branch name that no longer has scalars tied to the metric_name. + * no longer valid. * @param aggregateMetricSpec object with AggregateMetricSpecDao key value pairs */ function populateSpecInputs(aggregateMetricSpec) { @@ -399,15 +412,6 @@ $(document).ready(function () { $('#aggregateMetricSpecName').val(aggregateMetricSpec.name); $('#aggregateMetricSpecDescription').val(aggregateMetricSpec.description); $('#aggregateMetricSpecSpec').val(aggregateMetricSpec.spec); - // Skip value if it is 0 and comparison is empty, this was added as a DB - // default and wouldn't be allowed by the UI validation logic. - if (aggregateMetricSpec.value && - (aggregateMetricSpec.value != 0 || aggregateMetricSpec.comparison)) { - $('#aggregateMetricSpecValue').val(aggregateMetricSpec.value); - } - if (aggregateMetricSpec.comparison) { - $('#aggregateMetricSpecComparison').val(aggregateMetricSpec.comparison); - } var specParts = parseMetricSpec(aggregateMetricSpec.spec); $('#aggregateMetricSpecParam').val(specParts.param); $('#aggregateMetricSpecAggregateMetric').val(specParts.metric); @@ -416,7 +420,6 @@ $(document).ready(function () { $('#aggregateMetricSpecValidationError').text("Loaded metric name '"+specParts.metricName+"' is invalid"); } else { $('#aggregateMetricSpecMetricName').val(specParts.metricName); - $('#aggregateMetricSpecBranch').val(aggregateMetricSpec.branch); } $('#aggregateMetricSpecSaveLoading').hide(); } @@ -466,6 +469,241 @@ $(document).ready(function () { unhighlightActiveRow(); }); + //:~ Notification/Alerts panel + + /** + * Add a row to the notifications table for a given spec, based on the + * passed in AggregateMetricNotification object. + * @param aggregateMetricNotification object with AggregateMetricNotificationDao key value pairs + */ + function addToNotificationTable(notification) { + + var notificationId = notification.aggregate_metric_notification_id; + function createActionLink(qtip, actionClass, imgPath, label) { + var actionLink = ' '; + actionLink += ' '+label+''; + return actionLink; + } + + var row = '' + notification.branch + ''; + row += '' + notification.comparison + ''; + row += '' + notification.value + ''; + row += createActionLink('Edit notification', 'editAggregateMetricNotification', '/public/images/icons/edit.png', 'Edit'); + row += createActionLink('Edit users', 'editAggregateMetricNotificationUsers', '/public/images/icons/email_error.png', 'Users'); + row += createActionLink('Remove notification', 'removeAggregateMetricNotification', '/public/images/icons/close.png', 'Delete'); + row += ''; + $('#aggregateMetricNotificationsTable tbody').append(row); + } + + /** Remove highlight from active notification row. */ + function unhighlightActiveAlertRow() { + $('#aggregateMetricNotificationsTable tbody tr').each(function (ind, elem) { + $(this).removeClass('activeRow'); + }); + $('#aggregateMetricNotificationEdit').hide(); + $('#aggregateMetricNotificationUsers').hide(); + $('#aggregateMetricNotificationCancel').show(); + } + + /** + * Highlight the alert row which houses the current action in the Notifications table, + * sets the activeNotification closure variable to the alert in the row. + * @param element actionLink the anchor element that was clicked. + */ + function activateAlertRow(actionLink) { + unhighlightActiveAlertRow(); + $('#aggregateMetricNotificationValidationError').text(''); + actionLink.closest('tr').addClass('activeRow'); + $('#aggregateMetricNotificationCancel').hide(); + var notificationId = actionLink.data('aggregate_metric_notification_id'); + activeNotification = activeSpecNotifications[notificationId]; + } + + /** + * Validates the current notification input fields, whether for an edited + * notification or a new one. + * @return bool indicating whether validation succeeded. + */ + function validateNotification() { + var branch = $('#aggregateMetricNotificationBranch').val(); + if (branch === null || branch === '') { + $('#aggregateMetricNotificationValidationError').text('branch cannot be empty'); + return false; + } + var comparison = $('#aggregateMetricNotificationComparison').val(); + if (comparison === null || comparison === '') { + $('#aggregateMetricNotificationValidationError').text('comparison cannot be empty'); + return false; + } + var value = $('#aggregateMetricNotificationValue').val(); + if (value === null || value === '' || !$.isNumeric(value)) { + $('#aggregateMetricNotificationValidationError').text('value must be numeric'); + return false; + } + $('#aggregateMetricNotificationValidationError').text(''); + return true; + } + + /** + * Deactivate the current notification and hide any notification details panels. + */ + function hideNotificationDetailPanel() { + $('.editAlert').hide(); + $('.createAlert').hide(); + $('#aggregateMetricNotificationSaveLoading').hide(); + $('div#aggregateMetricNotificationSaveState input').prop('disabled', false); + unhighlightActiveAlertRow(); + $('#aggregateMetricNotificationEdit').hide(); + $('#aggregateMetricNotificationCancel').show(); + } + + // Notification panel handlers + // Notifications and Alerts are considered equivalent, "Alert" is shorter + + /** + * Handler for edit notification users action, activates the notification + * and loads any users tied to the notification to display them in the + * users table. + * The handler is tied to a static parent as the links can be + * dynamically generated through creation of new alerts. + */ + $('#aggregateMetricNotificationsTable').on('click', 'a.editAggregateMetricNotificationUsers', function() { + activateAlertRow($(this)); + $('#aggregateMetricNotificationUsers').show(); + $('#aggregateMetricSpecAlertedUsers').find('tr:gt(0)').remove(); + for(var userInd = 0; userInd < activeNotification.users.length; userInd += 1) { + var user = activeNotification.users[userInd]; + addToAlertedUsersTable(user.firstname +' '+user.lastname, user.user_id); + } + addClassesToTableRows('aggregateMetricSpecAlertedUsers'); + }); + + /** + * Handler for edit notification action, activates the notification + * and loads the notification into fields such that it can be edited. + * The handler is tied to a static parent as the links can be + * dynamically generated through creation of new alerts. + */ + $('#aggregateMetricNotificationsTable').on('click', 'a.editAggregateMetricNotification', function() { + activateAlertRow($(this)); + $('#aggregateMetricNotificationEdit').show(); + $('#aggregateMetricNotificationBranch').val(activeNotification.notification.branch); + $('#aggregateMetricNotificationValue').val(activeNotification.notification.value); + $('#aggregateMetricNotificationComparison').val(activeNotification.notification.comparison); + $('#aggregateMetricNotificationCreate').hide(); + $('#aggregateMetricNotificationUpdate').show(); + $('.editAlert').show(); + $('.createAlert').hide(); + }); + + /** + * Handler for Remove notification action, delete the notification and + * any associated alerted users. + * The handler is tied to a static parent as the links can be + * dynamically generated through creation of new alerts. + */ + $('#aggregateMetricNotificationsTable').on('click', 'a.removeAggregateMetricNotification', function() { + hideNotificationDetailPanel(); + var row = $(this).closest('tr'); + activateAlertRow($(this)); + var notificationId = $(this).data('aggregate_metric_notification_id'); + $('#aggregateMetricNotificationRemoveLoading').show(); + aggregatemetricnotificationRest('DELETE', notificationId, {}, function (retVal) { + row.remove(); + $('#aggregateMetricNotificationRemoveLoading').hide(); + delete activeSpecNotifications[notificationId]; + unhighlightActiveAlertRow(); + addClassesToTableRows('aggregateMetricNotificationsTable'); + }); + }); + + /** + * Handler for adding a new notification to the active Spec. + */ + $('#addAggregateMetricNotification').click(function () { + unhighlightActiveAlertRow(); + $('#aggregateMetricNotificationUpdate').hide(); + $('#aggregateMetricNotificationBranch').val(''); + $('#aggregateMetricNotificationComparison').val(''); + $('#aggregateMetricNotificationValue').val(''); + $('#aggregateMetricNotificationCreate').show(); + $('#aggregateMetricNotificationEdit').show(); + $('div#aggregateMetricNotificationSaveState input').prop('disabled', false); + $('#aggregateMetricNotificationValidationError').text(''); + $('#aggregateMetricNotificationSaveState').show(); + $('#aggregateMetricNotificationCancel').hide(); + $('.editAlert').hide(); + $('.createAlert').show(); + }); + + // Notification panel button handlers + + /** + * Handler for Cancel button: + * hide any notification detail panel and de-activate any notification row. + */ + $('#aggregateMetricNotificationCancel').click(function () { + $('#aggregateMetricUserAlerts').hide(); + unhighlightActiveAlertRow(); + unhighlightActiveRow(); + hideNotificationDetailPanel(); + }); + + /** + * Update the active notification with the input fields. + */ + $('input#aggregateMetricNotificationUpdate').click(function () { + if (validateNotification()) { + $('div#aggregateMetricNotificationSaveState input').prop('disabled', true); + $('#aggregateMetricNotificationSaveLoading').show(); + var notificationUpdates = { + branch: $('#aggregateMetricNotificationBranch').val(), + comparison: $('#aggregateMetricNotificationComparison').val(), + value: $('#aggregateMetricNotificationValue').val() + }; + var notificationId = activeNotification.notification.aggregate_metric_notification_id; + aggregatemetricnotificationRest('PUT', notificationId, notificationUpdates, function (retVal) { + activeSpecNotifications[notificationId].notification = retVal; + $('#aggregateMetricNotificationsTable td#amnBranch'+notificationId).html(retVal.branch); + $('#aggregateMetricNotificationsTable td#amnValue'+notificationId).html(retVal.value); + $('#aggregateMetricNotificationsTable td#amnComparison'+notificationId).html(retVal.comparison); + hideNotificationDetailPanel(); + }); + } + }); + + /** + * Cancel editing or creating a notification. + */ + $('#aggregateMetricNotificationSaveCancel').click(function () { + hideNotificationDetailPanel(); + }); + + /** + * Create a new notification with the input fields tied to the active Spec. + */ + $('input#aggregateMetricNotificationCreate').click(function () { + if (validateNotification()) { + $('div#aggregateMetricNotificationSaveState input').prop('disabled', true); + var notificationProperties = { + aggregate_metric_spec_id: $('#aggregateMetricSpecEditId').val(), + branch: $('#aggregateMetricNotificationBranch').val(), + comparison: $('#aggregateMetricNotificationComparison').val(), + value: $('#aggregateMetricNotificationValue').val() + }; + $('#aggregateMetricNotificationSaveLoading').show(); + aggregatemetricnotificationRest('POST', null, notificationProperties, function (retVal) { + hideNotificationDetailPanel(); + addToNotificationTable(retVal); + activeSpecNotifications[retVal.aggregate_metric_notification_id] = { + notification: retVal, + users: [] + }; + addClassesToTableRows('aggregateMetricNotificationsTable'); + }); + } + }); + //:~ Alerted Users panel /** @@ -476,13 +714,13 @@ $(document).ready(function () { function addToAlertedUsersTable(userName, userId) { function createActionLink(qtip, actionClass, imgPath, label) { - var actionLink = ' '; - actionLink += ' '+label+''; + var actionLink = ' '; + actionLink += ' '+label+''; return actionLink; } var row = '' + userName + ''; - row += createActionLink('Remove user from alerts', 'removeAlertedUser', '/public/images/icons/close.png', 'Remove alerts'); + row += createActionLink('Remove user from alerts', 'removeAlertedUser', '/public/images/icons/close.png', 'Remove alert'); row += ''; $('#aggregateMetricSpecAlertedUsers tbody').append(row); } @@ -497,12 +735,10 @@ $(document).ready(function () { $('#aggregateMetricSpecAlertedUsers').on('click', 'a.removeAlertedUser', function() { var row = $(this).closest('tr'); row.addClass('activeRow'); - var aggregateMetricSpecId = $('#aggregateMetricSpecEditId').val(); $('#aggregateMetricSpecAlertsLoading').show(); var userId = $(this).data('user_id'); - var jsonMethod = 'midas.tracker.aggregatemetricspecnotifieduser.delete'; - var args = 'aggregateMetricSpecId=' + aggregateMetricSpecId + '&userId=' + userId; + var args = 'aggregateMetricNotificationId=' + activeNotification.notification.aggregate_metric_notification_id + '&userId=' + userId; callAjaxWebApi(jsonMethod, 'POST', args, function (retVal) { if (retVal.data && retVal.data.user_id == userId) { row.remove(); @@ -516,6 +752,7 @@ $(document).ready(function () { }); // Live search for users + $.widget('custom.catcomplete', $.ui.autocomplete, { _renderMenu: function (ul, items) { 'use strict'; @@ -570,12 +807,11 @@ $(document).ready(function () { $('#aggregateMetricSpecAlertsLoading').show(); var userId = ui.item.userid; var userName = ui.item.value; - var aggregateMetricSpecId = $('#aggregateMetricSpecEditId').val(); - var jsonMethod = 'midas.tracker.aggregatemetricspecnotifieduser.create'; - var args = 'aggregateMetricSpecId=' + aggregateMetricSpecId + '&userId=' + userId; + var args = 'aggregateMetricNotificationId=' + activeNotification.notification.aggregate_metric_notification_id + '&userId=' + userId; callAjaxWebApi(jsonMethod, 'POST', args, function (retVal) { if (retVal.data && retVal.data.user_id == userId) { + activeNotification.users.push(retVal.data); addToAlertedUsersTable(userName, userId); addClassesToTableRows('aggregateMetricSpecAlertedUsers'); $('#addAlertUserSearchValue').val('init'); @@ -606,8 +842,7 @@ $(document).ready(function () { /** Handler for Alerts Users Done button, hide the alerts panel. */ $('input#aggregateMetricSpecUserAlertsDone').click(function () { - $('div#aggregateMetricUserAlerts').hide(); - unhighlightActiveRow(); + hideNotificationDetailPanel(); }); // Initialize the dialog now that it is loaded. diff --git a/modules/tracker/public/scss/producer/producer.aggregatemetric.scss b/modules/tracker/public/scss/producer/producer.aggregatemetric.scss index da5fafc90..dcb6ed6fd 100644 --- a/modules/tracker/public/scss/producer/producer.aggregatemetric.scss +++ b/modules/tracker/public/scss/producer/producer.aggregatemetric.scss @@ -1,232 +1,129 @@ // Midas Server. Copyright Kitware SAS. Licensed under the Apache License 2.0. -a { - &.aggregateMetricSpecAction { - color: #56758b; - - &:hover { - background-color: #E5E5E5; - cursor: pointer; - } - } - - &.alertedUsersAction { - color: #56758b; - - &:hover { - background-color: #E5E5E5; - cursor: pointer; - } - } -} - -div { - &#addAggregateMetricSpec { - margin-top: 10px; - } - - &#aggregateMetricSpecList { - margin-top: 10px; - } - - &.aggregateMetricSpecCreate { - border-top: 2px solid darkblue !important; - } +div#aggregateMetricSpecManage { + table { + width: 100%; - &.aggregateMetricSpecEdit { - border-top: 2px solid darkblue !important; - } + &.actionTable { + table-layout: fixed; + border: 2px solid #ddd; + margin-top: 15px; + margin-bottom: 15px; - &#aggregateMetricSpecEditWarning { - padding-top: 10px; - padding-bottom: 10px; - color: orange; - } + tr.activeRow { + border: 2px solid darkblue; + background-color: #c0d1fe !important; + } - &#aggregateMetricUserAlerts { - border-top: 2px solid darkblue; - color: #555; - font-size: 13px; - margin-top: 15px; - margin-bottom: 10px; - padding-top: 10px; - text-align: center; + tr.even { + background-color: #f4f4f4; + } - div#aggregateMetricUserAlertsThreshold { - margin-top: 15px; - margin-bottom: 10px; + th { + border-bottom: solid 1px black; - table#aggregateMetricUserAlertsThresholdDefinition { - margin-top: 10px; + &:last-of-type { + text-align: center; + border-left: dotted 1px black; + width: 30%; + } + } - td:first-of-type { - text-align: left; + td { + &:last-of-type { + border-left: dotted 1px black; } } - } - textarea#aggregateMetricUserAlertsSpec { - margin-top: 10px; - width: 100%; - } + span.actionsList { + display: flex; + justify-content: space-around; - div#addAggregateMetricSpecAlertUser { - margin-top: 15px; - text-align: center; + a:first-of-type { + padding-left: 5px; + } + } } - - div.alertUserSearch { - margin-top: 10px; - + &.fieldTable { input { width: 100%; } + select { + width: 100%; + } } } - &.aggregateMetricSectionTitle { - border-top: 1px solid #d7d7d7; - color: #555; - font-size: 13px; - margin-top: 15px; - margin-bottom: 10px; - padding-top: 10px; - text-align: center; - } - - - &.resultingMetricText { - color: #555; - font-size: 12px; - margin-top: 10px; - text-align: center; - } - - &#aggregateMetricSpecUserAlertsSaveState { - margin-top: 20px; - - input { - background: #f6f9fe; - border: 1px solid #808080; - color: #2e6e9e; - cursor: pointer; - float: right; - margin-left: 10px; - } - } - - &#aggregateMetricSpecSaveState { - margin-top: 20px; + a.actionLink { + color: #56758b; - input { - background: #f6f9fe; - border: 1px solid #808080; - color: #2e6e9e; + &:hover { + background-color: #E5E5E5; cursor: pointer; - float: right; - margin-left: 10px; - } - - input:disabled { - color: #c0c0c0; - cursor: not-allowed; } } - - -} - -label { - &#aggregateMetricSpecValidationError { + label.validationError { color: crimson; } -} - -img { - &#aggregateMetricSpecSaveLoading { - float: left; - margin-right: 15px; - } - - &#aggregateMetricSpecDeleteLoading { - float: right; - margin-right: 40px; - } - - &#aggregateMetricSpecAlertsLoading { - float: left; - } -} - -table { - - &#aggregateMetricSpecAlertedUsers { - table-layout: fixed; - border: 2px solid #ddd; - width: 100%; - th { - border-bottom: solid 1px black; + div { + &.subsectionTitle { + border-top: 2px solid darkblue; + margin-top: 15px; + margin-bottom: 15px; + padding-top: 10px; + color: #555; + font-size: 13px; text-align: center; - - &:first-of-type { - width: 70%; - border-right: dotted 1px black; - } + font-weight: bold; } - - tr.even { - background-color: #f4f4f4; - } - - td.userName { - border-right: dotted 1px black; - text-align: left; - } - - tr.activeRow { - border: 2px solid darkblue; - background-color: #c0d1fe; + &.subsubsectionTitle { + color: #555; + font-size: 12px; + margin-top: 10px; + margin-bottom: 10px; + text-align: center; } - } - - - &#aggregateMetricSpecListTable { - table-layout: fixed; - border: 2px solid #ddd; - width: 100%; + &.saveState { + margin-top: 15px; - th { - border-bottom: solid 1px black; - text-align: center; + input { + background: #f6f9fe; + border: 1px solid #808080; + color: #2e6e9e; + cursor: pointer; + float: right; + margin-left: 10px; + } - &:first-of-type { - width: 70%; - border-right: dotted 1px black; + input:disabled { + color: #c0c0c0; + cursor: not-allowed; } } - - td.specName { - border-right: dotted 1px black; + &#aggregateMetricSpecEditWarning { + padding-top: 10px; + padding-bottom: 10px; + color: orange; } + } - tr.even { - background-color: #f4f4f4; - } + img.loadingImg { + float: left; - tr.activeRow { - border: 2px solid darkblue; - background-color: #c0d1fe; + &#aggregateMetricSpecDeleteLoading { + float: right; + margin-right: 40px; } + } - span.actionsList { - display: flex; - justify-content: space-around; + textarea#aggregateMetricUserAlertsSpec { + margin-top: 10px; + width: 100%; + } - a:first-of-type { - padding-left: 5px; - } - } + input#addAlertUserSearch { + width: 100% } } diff --git a/modules/tracker/tests/controllers/ApiAggregatemetricnotificationComponentTest.php b/modules/tracker/tests/controllers/ApiAggregatemetricnotificationComponentTest.php new file mode 100644 index 000000000..a3a498fe4 --- /dev/null +++ b/modules/tracker/tests/controllers/ApiAggregatemetricnotificationComponentTest.php @@ -0,0 +1,227 @@ +enabledModules = array('api', 'scheduler', $this->moduleName); + $this->_models = array('Assetstore', 'Community', 'Setting', 'User'); + $this->setupDatabase(array('default')); + $this->setupDatabase(array('aggregateMetric'), 'tracker'); + + ControllerTestCase::setUp(); + } + + /** + * Test getting an existing existing aggregate metric notification with a set of params, via GET. + * + * @throws Zend_Exception + */ + public function testGET() + { + $usersFile = $this->loadData('User', 'default'); + /** @var UserDao $userDao */ + $userDao = $this->User->load($usersFile[0]->getKey()); + $token = $this->_loginAsAdministrator(); + + $restParams = array( + 'token' => $token, + ); + $this->resetAll(); + $this->params = $restParams; + $resp = $this->_callRestApi('GET', '/tracker/aggregatemetricnotification/1'); + + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', 'tracker'); + /** @var Tracker_AggregateMetricNotificationDao $notificationDao */ + $notificationDao = $aggregateMetricNotificationModel->initDao('AggregateMetricNotification', json_decode(json_encode($resp['body']), true), $this->moduleName); + + $this->assertEquals($notificationDao->getAggregateMetricSpecId(), '1'); + $this->assertEquals($notificationDao->getBranch(), 'master'); + $this->assertEquals($notificationDao->getComparison(), '>'); + $this->assertEquals($notificationDao->getValue(), '19.0'); + } + + /** + * Test creating an existing aggregate metric notification with a set of params, via POST. + * + * @throws Zend_Exception + */ + public function testPOST() + { + $usersFile = $this->loadData('User', 'default'); + /** @var UserDao $userDao */ + $userDao = $this->User->load($usersFile[0]->getKey()); + $token = $this->_loginAsAdministrator(); + + $restParams = array( + 'token' => $token, + 'aggregate_metric_spec_id' => 1, + 'branch' => 'POST TEST', + 'comparison' => '==', + 'value' => '16.0', + ); + + $this->resetAll(); + $this->params = $restParams; + $resp = $this->_callRestApi('POST', '/tracker/aggregatemetricnotification/'); + + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', 'tracker'); + /** @var Tracker_AggregateMetricNotificationDao $notificationDao */ + $notificationDao = $aggregateMetricNotificationModel->initDao('AggregateMetricNotification', json_decode(json_encode($resp['body']), true), $this->moduleName); + + // Test the result of the API call. + $this->assertEquals($notificationDao->getAggregateMetricSpecId(), $restParams['aggregate_metric_spec_id']); + $this->assertEquals($notificationDao->getValue(), $restParams['value']); + $this->assertEquals($notificationDao->getComparison(), $restParams['comparison']); + $this->assertEquals($notificationDao->getBranch(), $restParams['branch']); + + // Load from the DB and test again. + $notificationDao = $aggregateMetricNotificationModel->load($notificationDao->getAggregateMetricNotificationId()); + + $this->assertEquals($notificationDao->getAggregateMetricSpecId(), $restParams['aggregate_metric_spec_id']); + $this->assertEquals($notificationDao->getValue(), $restParams['value']); + $this->assertEquals($notificationDao->getComparison(), $restParams['comparison']); + $this->assertEquals($notificationDao->getBranch(), $restParams['branch']); + + // Delete to clean up. + $aggregateMetricNotificationModel->delete($notificationDao); + } + + /** + * Test updating an existing aggregate metric notification with a set of params, via PUT. + * + * @throws Zend_Exception + */ + public function testPUT() + { + $usersFile = $this->loadData('User', 'default'); + /** @var UserDao $userDao */ + $userDao = $this->User->load($usersFile[0]->getKey()); + $token = $this->_loginAsAdministrator(); + + $originalParams = array( + 'token' => $token, + 'aggregate_metric_spec_id' => 1, + 'branch' => 'master', + 'comparison' => '>', + 'value' => 19.0, + ); + + $restParams = array( + 'token' => $token, + 'aggregate_metric_spec_id' => 2, + 'branch' => 'retsam', + 'comparison' => '!=', + 'value' => 21.0, + ); + + $this->resetAll(); + $this->params = $restParams; + $resp = $this->_callRestApi('PUT', '/tracker/aggregatemetricnotification/1'); + + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', 'tracker'); + /** @var Tracker_AggregateMetricNotificationDao $notificationDao */ + $notificationDao = $aggregateMetricNotificationModel->initDao('AggregateMetricNotification', json_decode(json_encode($resp['body']), true), $this->moduleName); + + // Test the result of the API call. + // The aggregate_metric_spec_id should not have changed. + $this->assertEquals($notificationDao->getAggregateMetricSpecId(), $originalParams['aggregate_metric_spec_id']); + $this->assertEquals($notificationDao->getValue(), $restParams['value']); + $this->assertEquals($notificationDao->getComparison(), $restParams['comparison']); + $this->assertEquals($notificationDao->getBranch(), $restParams['branch']); + + // Load from the DB and test again. + $notificationDao = $aggregateMetricNotificationModel->load($notificationDao->getAggregateMetricNotificationId()); + + // The aggregate_metric_spec_id should not have changed. + $this->assertEquals($notificationDao->getAggregateMetricSpecId(), $originalParams['aggregate_metric_spec_id']); + $this->assertEquals($notificationDao->getValue(), $restParams['value']); + $this->assertEquals($notificationDao->getComparison(), $restParams['comparison']); + $this->assertEquals($notificationDao->getBranch(), $restParams['branch']); + + // Reset via PUT to the original state. + $this->resetAll(); + $this->params = $originalParams; + $resp = $this->_callRestApi('PUT', '/tracker/aggregatemetricnotification/1'); + + // Load from the DB and test again. + $notificationDao = $aggregateMetricNotificationModel->load($notificationDao->getAggregateMetricNotificationId()); + + $this->assertEquals($notificationDao->getAggregateMetricSpecId(), $originalParams['aggregate_metric_spec_id']); + $this->assertEquals($notificationDao->getValue(), $originalParams['value']); + $this->assertEquals($notificationDao->getComparison(), $originalParams['comparison']); + $this->assertEquals($notificationDao->getBranch(), $originalParams['branch']); + } + + /** + * Test deleting an existing aggregate metric spec, via DELETE. + * + * @throws Zend_Exception + */ + public function testDELETE() + { + $usersFile = $this->loadData('User', 'default'); + /** @var UserDao $userDao */ + $userDao = $this->User->load($usersFile[0]->getKey()); + $token = $this->_loginAsAdministrator(); + + // Create a notification via POST. + + $restParams = array( + 'token' => $token, + 'aggregate_metric_spec_id' => 1, + 'branch' => 'DELETE TEST', + 'comparison' => '==', + 'value' => '16.0', + ); + + $this->resetAll(); + $this->params = $restParams; + $resp = $this->_callRestApi('POST', '/tracker/aggregatemetricnotification/'); + + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', 'tracker'); + /** @var Tracker_AggregateMetricNotificationDao $notificationDao */ + $notificationDao = $aggregateMetricNotificationModel->initDao('AggregateMetricNotification', json_decode(json_encode($resp['body']), true), $this->moduleName); + + // Load from the DB and test properties. + $notificationDao = $aggregateMetricNotificationModel->load($notificationDao->getAggregateMetricNotificationId()); + $this->assertEquals($notificationDao->getAggregateMetricSpecId(), $restParams['aggregate_metric_spec_id']); + $this->assertEquals($notificationDao->getValue(), $restParams['value']); + $this->assertEquals($notificationDao->getComparison(), $restParams['comparison']); + $this->assertEquals($notificationDao->getBranch(), $restParams['branch']); + + $notificationId = $notificationDao->getAggregateMetricNotificationId(); + $resp = $this->_callRestApi('DELETE', '/tracker/aggregatemetricnotification/'.$notificationId); + + $notificationDao = $aggregateMetricNotificationModel->load($notificationId); + $this->assertEquals($notificationDao, false); + } +} diff --git a/modules/tracker/tests/controllers/ApiAggregatemetricspecComponentTest.php b/modules/tracker/tests/controllers/ApiAggregatemetricspecComponentTest.php index 448751d2f..b42eef728 100644 --- a/modules/tracker/tests/controllers/ApiAggregatemetricspecComponentTest.php +++ b/modules/tracker/tests/controllers/ApiAggregatemetricspecComponentTest.php @@ -32,12 +32,7 @@ public function setUp() $this->_models = array('Assetstore', 'Community', 'Setting', 'User'); $this->setupDatabase(array('default')); $this->setupDatabase(array('aggregateMetric'), 'tracker'); - $db = Zend_Registry::get('dbAdapter'); - $configDatabase = Zend_Registry::get('configDatabase'); - if ($configDatabase->database->adapter == 'PDO_PGSQL') { - $db->query("SELECT setval('tracker_aggregate_metric_spec_aggregate_metric_spec_id_seq', (SELECT MAX(aggregate_metric_spec_id) FROM tracker_aggregate_metric_spec)+1);"); - $db->query("SELECT setval('tracker_scalar_scalar_id_seq', (SELECT MAX(scalar_id) FROM tracker_scalar)+1);"); - } + ControllerTestCase::setUp(); } @@ -66,9 +61,6 @@ public function testGET() $specDao = $aggregateMetricSpecModel->initDao('AggregateMetricSpec', json_decode(json_encode($resp['body']), true), $this->moduleName); $this->assertEquals($specDao->getProducerId(), '100'); - $this->assertEquals($specDao->getComparison(), '!='); - $this->assertEquals($specDao->getValue(), '1.0'); - $this->assertEquals($specDao->getBranch(), 'master'); $this->assertEquals($specDao->getName(), '95th Percentile Greedy error'); $this->assertEquals($specDao->getDescription(), '95th Percentile Greedy error'); $this->assertEquals($specDao->getSpec(), "percentile('Greedy error', 95)"); @@ -89,11 +81,8 @@ public function testPOST() $restParams = array( 'token' => $token, 'producer_id' => 100, - 'branch' => 'newbranch', 'name' => 'POST 23 percentile', 'description' => 'opaque', - 'value' => '23', - 'comparison' => '==', 'spec' => "percentile('POST', 23)", ); @@ -108,9 +97,6 @@ public function testPOST() // Test the result of the API call. $this->assertEquals($specDao->getProducerId(), $restParams['producer_id']); - $this->assertEquals($specDao->getComparison(), $restParams['comparison']); - $this->assertEquals($specDao->getValue(), $restParams['value']); - $this->assertEquals($specDao->getBranch(), $restParams['branch']); $this->assertEquals($specDao->getName(), $restParams['name']); $this->assertEquals($specDao->getDescription(), $restParams['description']); $this->assertEquals($specDao->getSpec(), $restParams['spec']); @@ -119,9 +105,6 @@ public function testPOST() $specDao = $aggregateMetricSpecModel->load($specDao->getAggregateMetricSpecId()); $this->assertEquals($specDao->getProducerId(), $restParams['producer_id']); - $this->assertEquals($specDao->getComparison(), $restParams['comparison']); - $this->assertEquals($specDao->getValue(), $restParams['value']); - $this->assertEquals($specDao->getBranch(), $restParams['branch']); $this->assertEquals($specDao->getName(), $restParams['name']); $this->assertEquals($specDao->getDescription(), $restParams['description']); $this->assertEquals($specDao->getSpec(), $restParams['spec']); @@ -142,11 +125,8 @@ public function testPUT() $restParams = array( 'token' => $token, 'producer_id' => 200, - 'branch' => 'splitter', 'name' => 'NewAlgo 23 percentile', 'description' => 'vivid', - 'value' => '23', - // Don't change comparison, to test that an unset value won't change. 'spec' => "percentile('NewAlgo', 23)", ); @@ -161,9 +141,6 @@ public function testPUT() // Test the result of the API call. $this->assertEquals($specDao->getProducerId(), $restParams['producer_id']); - $this->assertEquals($specDao->getComparison(), '!='); - $this->assertEquals($specDao->getValue(), $restParams['value']); - $this->assertEquals($specDao->getBranch(), $restParams['branch']); $this->assertEquals($specDao->getName(), $restParams['name']); $this->assertEquals($specDao->getDescription(), $restParams['description']); $this->assertEquals($specDao->getSpec(), $restParams['spec']); @@ -172,9 +149,6 @@ public function testPUT() $specDao = $aggregateMetricSpecModel->load(1); $this->assertEquals($specDao->getProducerId(), $restParams['producer_id']); - $this->assertEquals($specDao->getComparison(), '!='); - $this->assertEquals($specDao->getValue(), $restParams['value']); - $this->assertEquals($specDao->getBranch(), $restParams['branch']); $this->assertEquals($specDao->getName(), $restParams['name']); $this->assertEquals($specDao->getDescription(), $restParams['description']); $this->assertEquals($specDao->getSpec(), $restParams['spec']); diff --git a/modules/tracker/tests/controllers/ApiComponentTest.php b/modules/tracker/tests/controllers/ApiComponentTest.php index 64753d5de..c2999d010 100644 --- a/modules/tracker/tests/controllers/ApiComponentTest.php +++ b/modules/tracker/tests/controllers/ApiComponentTest.php @@ -35,14 +35,6 @@ public function setUp() $this->enabledModules = array('api', 'scheduler', $this->moduleName); $this->_models = array('Assetstore', 'Community', 'Setting', 'User'); - $db = Zend_Registry::get('dbAdapter'); - $configDatabase = Zend_Registry::get('configDatabase'); - if ($configDatabase->database->adapter == 'PDO_PGSQL') { - $db->query("SELECT setval('tracker_trend_trend_id_seq', (SELECT MAX(trend_id) FROM tracker_trend)+1);"); - $db->query("SELECT setval('tracker_submission_submission_id_seq', (SELECT MAX(submission_id) FROM tracker_submission)+1);"); - $db->query("SELECT setval('tracker_scalar_scalar_id_seq', (SELECT MAX(scalar_id) FROM tracker_scalar)+1);"); - } - ControllerTestCase::setUp(); } @@ -55,21 +47,33 @@ public function testUploadScalarWithSubmission() { $uuidComponent = MidasLoader::loadComponent('Uuid'); $uuid = $uuidComponent->generate(); + $uuid2 = $uuidComponent->generate(); + $uuid3 = $uuidComponent->generate(); $token = $this->_loginAsAdministrator(); - $outputs = array(); - $outputs['metric_0'] = $this->_submitScalar($token, $uuid, 'metric_0', '18'); $metric1Params = array('num_param' => 19.0, 'text_param' => 'metric1 text', 'null_param' => null); - $outputs['metric_1'] = $this->_submitScalar($token, $uuid, 'metric_1', '19', 'meters', $metric1Params); $metric2Params = array('num_param' => 20.0, 'text_param' => 'metric2 text', 'null_param' => null); - $outputs['metric_2'] = $this->_submitScalar($token, $uuid, 'metric_2', '20', 'mm', $metric2Params); + $this->_submitSubmission($token, $uuid); + $this->_submitSubmission($token, $uuid2, $metric1Params); + $this->_submitSubmission($token, $uuid3, $metric2Params); + $outputs = array(); + $outputs['metric_0'] = $this->_submitScalar($token, $uuid, 'metric_0', '18'); + $outputs['metric_1'] = $this->_submitScalar($token, $uuid2, 'metric_1', '19', 'meters'); + $outputs['metric_2'] = $this->_submitScalar($token, $uuid3, 'metric_2', '20', 'mm'); /** @var Tracker_SubmissionModel $submissionModel */ $submissionModel = MidasLoader::loadModel('Submission', 'tracker'); /** @var Tracker_SubmissionDao $submissionDao */ $submissionDao = $submissionModel->getSubmission($uuid); + + /** @var Tracker_SubmissionDao $submissionDao2 */ + $submissionDao2 = $submissionModel->getSubmission($uuid2); + + /** @var Tracker_SubmissionDao $submissionDao3 */ + $submissionDao3 = $submissionModel->getSubmission($uuid3); + $scalarDaos = $submissionModel->getScalars($submissionDao); // Maps the scalars for each metric. @@ -84,9 +88,9 @@ public function testUploadScalarWithSubmission() } // Params should be a zero element array here. - $this->assertTrue(!($metricToScalar['metric_0']->getParams())); + $this->assertTrue(!($submissionDao->getParams())); - $metric1Params = $metricToScalar['metric_1']->getParams(); + $metric1Params = $submissionDao2->getParams(); $metric1ParamChecks = array( 'num_param' => array('found' => false, 'type' => 'numeric', 'val' => 19.0), 'text_param' => array('found' => false, 'type' => 'text', 'val' => 'metric1 text'), @@ -110,7 +114,7 @@ public function testUploadScalarWithSubmission() $this->assertTrue($checks['found']); } - $metric2Params = $metricToScalar['metric_2']->getParams(); + $metric2Params = $submissionDao3->getParams(); $metric2ParamChecks = array( 'num_param' => array('found' => false, 'type' => 'numeric', 'val' => 20.0), 'text_param' => array('found' => false, 'type' => 'text', 'val' => 'metric2 text'), @@ -133,6 +137,11 @@ public function testUploadScalarWithSubmission() foreach ($metric2ParamChecks as $checks) { $this->assertTrue($checks['found']); } + + // clean up + $submissionModel->delete($submissionDao); + $submissionModel->delete($submissionDao2); + $submissionModel->delete($submissionDao3); } /** @@ -152,7 +161,6 @@ private function _submitScalar($token, $uuid, $metric, $value, $unit = false, $s $this->params['method'] = 'midas.tracker.scalar.add'; $this->params['token'] = $token; $this->params['communityId'] = '2000'; - $this->params['producerDisplayName'] = 'Test Producer'; $this->params['metricName'] = $metric; $this->params['value'] = $value; $this->params['producerRevision'] = 'deadbeef'; @@ -169,25 +177,22 @@ private function _submitScalar($token, $uuid, $metric, $value, $unit = false, $s return $res->data; } - /** - * Test listing the branch names tied to a producer and trend metric_name. - * - * @throws Zend_Exception - */ - public function testBranchesformetricnameList() + private function _submitSubmission($token, $uuid, $params = false) { - $token = $this->_loginAsAdministrator(); $this->resetAll(); - $this->params['method'] = 'midas.tracker.branchesformetricname.list'; + $this->params['method'] = 'midas.tracker.submission.add'; $this->params['token'] = $token; - $this->params['producerId'] = '100'; - $this->params['trendMetricName'] = 'Greedy error'; + $this->params['communityId'] = '2000'; + $this->params['producerDisplayName'] = 'Test Producer'; + $this->params['producerRevision'] = 'deadbeef'; + $this->params['submitTime'] = 'now'; + $this->params['uuid'] = $uuid; + if ($params !== false) { + $this->params['params'] = json_encode($params); + } $res = $this->_callJsonApi(); - /** @var array branches */ - $branches = $res->data; - $this->assertEquals(count($branches), 2); - $this->assertTrue(in_array('master', $branches)); - $this->assertTrue(in_array('test', $branches)); + + return $res->data; } /** @@ -209,6 +214,8 @@ public function testAggregatemetricsUpdate() $submissionModel->createSubmission($producerDao, $uuid, 'Tmp submission'); /** @var Tracker_SubmissionDao $submissionDao */ $submissionDao = $submissionModel->getSubmission($uuid); + $submissionDao->setBranch('master'); + $submissionModel->save($submissionDao); // Create 4 scalars on the submission. @@ -223,18 +230,21 @@ public function testAggregatemetricsUpdate() /** @var UserDao $userDao */ $userDao = $authComponent->getUser(array('token' => $token), null); + /** @var array $scalars */ + $scalars = array(); + /** @var Tracker_TrendDao $greedyError1TrendDao */ $greedyError1TrendDao = $trendModel->load(1); - $scalarModel->addToTrend($greedyError1TrendDao, 'now', $submissionDao->getSubmissionId(), 'deadbeef', 101, $userDao, false, false, 'url', 'master'); + $scalars[] = $scalarModel->addToTrend($greedyError1TrendDao, $submissionDao, 101); /** @var Tracker_TrendDao $greedyError2TrendDao */ $greedyError2TrendDao = $trendModel->load(2); - $scalarModel->addToTrend($greedyError2TrendDao, 'now', $submissionDao->getSubmissionId(), 'deadbeef', 102, $userDao, false, false, 'url', 'master'); + $scalars[] = $scalarModel->addToTrend($greedyError2TrendDao, $submissionDao, 102); /** @var Tracker_TrendDao $greedyError3TrendDao */ $greedyError3TrendDao = $trendModel->load(3); - $scalarModel->addToTrend($greedyError3TrendDao, 'now', $submissionDao->getSubmissionId(), 'deadbeef', 103, $userDao, false, false, 'url', 'master'); + $scalars[] = $scalarModel->addToTrend($greedyError3TrendDao, $submissionDao, 103); /** @var Tracker_TrendDao $greedyError4TrendDao */ $greedyError4TrendDao = $trendModel->load(4); - $scalarModel->addToTrend($greedyError4TrendDao, 'now', $submissionDao->getSubmissionId(), 'deadbeef', 104, $userDao, false, false, 'url', 'master'); + $scalars[] = $scalarModel->addToTrend($greedyError4TrendDao, $submissionDao, 104); // Get existing aggregate metrics for this submission, there should be 0. @@ -243,12 +253,46 @@ public function testAggregatemetricsUpdate() /** array $aggregateMetrics */ $aggregateMetrics = $aggregateMetricModel->getAggregateMetricsForSubmission($submissionDao); + // Add users 1 & 2 to notification 1, 95th percentile Greedy error > 19.0 + // Add users 1 & 3 to notification 2, 55th percentile Greedy error != 11.0 + + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', 'tracker'); + + /** @var Tracker_AggregateMetricNotificationDao $amn95thPercentileGreedyError */ + $amn95thPercentileGreedyError = $aggregateMetricNotificationModel->load(1); + /** @var Tracker_AggregateMetricNotificationDao $amn55thPercentileGreedyError */ + $amn55thPercentileGreedyError = $aggregateMetricNotificationModel->load(2); + + /** @var UserModel $userModel */ + $userModel = MidasLoader::loadModel('User'); + /** @var UserDao $user1Dao */ + $user1Dao = $userModel->load(1); + /** @var UserDao $user2Dao */ + $user2Dao = $userModel->load(2); + /** @var UserDao $user3Dao */ + $user3Dao = $userModel->load(3); + + $aggregateMetricNotificationModel->createUserNotification($amn95thPercentileGreedyError, $user1Dao); + $aggregateMetricNotificationModel->createUserNotification($amn95thPercentileGreedyError, $user2Dao); + + $aggregateMetricNotificationModel->createUserNotification($amn55thPercentileGreedyError, $user1Dao); + $aggregateMetricNotificationModel->createUserNotification($amn55thPercentileGreedyError, $user3Dao); + + // Sadly, enabling a module does not import its constants. + require_once BASE_PATH.'/modules/scheduler/constant/module.php'; + /** @var Scheduler_JobModel $jobModel */ + $jobModel = MidasLoader::loadModel('Job', 'scheduler'); + // Ensure there aren't any notification jobs existing. + $this->assertEquals(0, count($jobModel->findBy('task', 'TASK_TRACKER_SEND_AGGREGATE_METRIC_NOTIFICATION'))); + // Call the API to update and return metrics for this submission. $this->resetAll(); $this->params['method'] = 'midas.tracker.aggregatemetrics.update'; $this->params['token'] = $token; $this->params['uuid'] = $uuid; + $this->params['notify'] = true; $resp = $this->_callJsonApi(); $aggregateMetrics = array(); /** stdClass $aggregateMetricStdClass */ @@ -305,8 +349,85 @@ public function testAggregatemetricsUpdate() $this->assertTrue($metricValue[key($metricValue)]); } - // Call delete on the submission so as to not interfere with other tests. + // Check that the correction notifications were scheduled. + + $expectedParams = array( + array( + 'aggregate_metric_notification_id' => '1', + 'aggregate_metric_id' => '1', + 'recipient_id' => '1', + 'found' => false, + ), + array( + 'aggregate_metric_notification_id' => '1', + 'aggregate_metric_id' => '1', + 'recipient_id' => '2', + 'found' => false, + ), + array( + 'aggregate_metric_notification_id' => '2', + 'aggregate_metric_id' => '2', + 'recipient_id' => '1', + 'found' => false, + ), + array( + 'aggregate_metric_notification_id' => '2', + 'aggregate_metric_id' => '2', + 'recipient_id' => '3', + 'found' => false, + ), + ); + + /** @var array $aggregateMetricNotificationJobs */ + $aggregateMetricNotificationJobs = $jobModel->findBy('task', 'TASK_TRACKER_SEND_AGGREGATE_METRIC_NOTIFICATION'); + $this->assertEquals(4, count($aggregateMetricNotificationJobs)); + /** @var Scheduler_JobDao $job */ + foreach ($aggregateMetricNotificationJobs as $job) { + /** @var string $params */ + $params = $job->getParams(); + preg_match("/\"aggregate_metric_notification_id\":\"(\d+)\",\"aggregate_metric_id\":\"(\d+)\",\"recipient_id\":\"(\d+)\"/", $params, $matches); + /** @var string $notificationId */ + $notificationId = $matches[1]; + /** @var string $metricId */ + $metricId = $matches[2]; + /** @var string $userId */ + $userId = $matches[3]; + + /** @var int $ind */ + /** @var array $expectedParam */ + foreach ($expectedParams as $ind => $expectedParam) { + if ($expectedParam['aggregate_metric_notification_id'] == $notificationId && + $expectedParam['aggregate_metric_id'] == $metricId && + $expectedParam['recipient_id'] == $userId) { + $expectedParams[$ind]['found'] = true; + break; + } + } + } + + // Check that all the expected jobs were found. + /** @var int $ind */ + /** @var array $expectedParam */ + foreach ($expectedParams as $ind => $expectedParam) { + $this->assertTrue($expectedParam['found']); + } + + // Clean up after the test so as to not interfere with other tests. + + // Delete all the jobs. + /** @var Scheduler_JobDao $job */ + foreach ($aggregateMetricNotificationJobs as $job) { + $jobModel->delete($job); + } + + // Delete the created submission. $submissionModel->delete($submissionDao); + + // Delete the users associated to notifications. + $aggregateMetricNotificationModel->deleteUserNotification($amn95thPercentileGreedyError, $user1Dao); + $aggregateMetricNotificationModel->deleteUserNotification($amn95thPercentileGreedyError, $user2Dao); + $aggregateMetricNotificationModel->deleteUserNotification($amn55thPercentileGreedyError, $user1Dao); + $aggregateMetricNotificationModel->deleteUserNotification($amn55thPercentileGreedyError, $user3Dao); } /** @@ -326,13 +447,23 @@ public function testAggregatemetricspecNotificationEndpoints() $userDao = $authComponent->getUser(array('token' => $token), null); $this->resetAll(); - $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifiedusers.list'; + $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifications.list'; $this->params['token'] = $token; $this->params['aggregateMetricSpecId'] = 1; $resp = $this->_callJsonApi(); /** @var array $notifiedUsers */ - $notifiedUsers = $resp->data; - $this->assertEquals(0, count($notifiedUsers)); + $notifications = $resp->data; + // Initialliy there is one notification with zero users. + $this->assertEquals(1, count($notifications)); + $this->assertEquals(0, count($notifications[0]->users)); + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', 'tracker'); + /** @var Tracker_AggregateMetricNotificationDao $notificationDao */ + $notificationDao = $aggregateMetricNotificationModel->initDao('AggregateMetricNotification', json_decode(json_encode($notifications[0]->notification), true), $this->moduleName); + $this->assertEquals($notificationDao->getAggregateMetricSpecId(), 1); + $this->assertEquals($notificationDao->getValue(), 19.0); + $this->assertEquals($notificationDao->getComparison(), '>'); + $this->assertEquals($notificationDao->getBranch(), 'master'); // Create one notified user. @@ -340,17 +471,22 @@ public function testAggregatemetricspecNotificationEndpoints() $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifieduser.create'; $this->params['token'] = $token; $this->params['userId'] = 1; - $this->params['aggregateMetricSpecId'] = 1; + $this->params['aggregateMetricNotificationId'] = $notificationDao->getAggregateMetricNotificationId(); $resp = $this->_callJsonApi(); $this->assertEquals(1, $resp->data->user_id); $this->resetAll(); - $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifiedusers.list'; + $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifications.list'; $this->params['token'] = $token; $this->params['aggregateMetricSpecId'] = 1; $resp = $this->_callJsonApi(); + /** @var array $notifications */ + $notifications = $resp->data; + // There should be one user on this notification. + $this->assertEquals(1, count($notifications)); + $this->assertEquals(1, count($notifications[0]->users)); /** @var array $notifiedUsers */ - $notifiedUsers = $resp->data; + $notifiedUsers = $notifications[0]->users; /** @var array $expectedUserIds */ $expectedUserIds = array( 1 => false, @@ -364,6 +500,12 @@ public function testAggregatemetricspecNotificationEndpoints() foreach ($expectedUserIds as $expectedUserId) { $this->assertTrue($expectedUserIds[$expectedUserId]); } + /** @var Tracker_AggregateMetricNotificationDao $notificationDao */ + $notificationDao = $aggregateMetricNotificationModel->initDao('AggregateMetricNotification', json_decode(json_encode($notifications[0]->notification), true), $this->moduleName); + $this->assertEquals($notificationDao->getAggregateMetricSpecId(), 1); + $this->assertEquals($notificationDao->getValue(), 19.0); + $this->assertEquals($notificationDao->getComparison(), '>'); + $this->assertEquals($notificationDao->getBranch(), 'master'); // Create a notification with the same user. @@ -371,16 +513,18 @@ public function testAggregatemetricspecNotificationEndpoints() $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifieduser.create'; $this->params['token'] = $token; $this->params['userId'] = 1; - $this->params['aggregateMetricSpecId'] = 1; + $this->params['aggregateMetricNotificationId'] = 1; $resp = $this->_callJsonApi(); $this->resetAll(); - $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifiedusers.list'; + $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifications.list'; $this->params['token'] = $token; $this->params['aggregateMetricSpecId'] = 1; $resp = $this->_callJsonApi(); + /** @var array $notifications */ + $notifications = $resp->data; /** @var array $notifiedUsers */ - $notifiedUsers = $resp->data; + $notifiedUsers = $notifications[0]->users; /** @var array $expectedUserIds */ $expectedUserIds = array( 1 => false, @@ -394,6 +538,12 @@ public function testAggregatemetricspecNotificationEndpoints() foreach ($expectedUserIds as $expectedUserId) { $this->assertTrue($expectedUserIds[$expectedUserId]); } + /** @var Tracker_AggregateMetricNotificationDao $notificationDao */ + $notificationDao = $aggregateMetricNotificationModel->initDao('AggregateMetricNotification', json_decode(json_encode($notifications[0]->notification), true), $this->moduleName); + $this->assertEquals($notificationDao->getAggregateMetricSpecId(), 1); + $this->assertEquals($notificationDao->getValue(), 19.0); + $this->assertEquals($notificationDao->getComparison(), '>'); + $this->assertEquals($notificationDao->getBranch(), 'master'); // Create a notification with a second user. @@ -401,17 +551,19 @@ public function testAggregatemetricspecNotificationEndpoints() $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifieduser.create'; $this->params['token'] = $token; $this->params['userId'] = 2; - $this->params['aggregateMetricSpecId'] = 1; + $this->params['aggregateMetricNotificationId'] = 1; $resp = $this->_callJsonApi(); $this->assertEquals(2, $resp->data->user_id); $this->resetAll(); - $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifiedusers.list'; + $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifications.list'; $this->params['token'] = $token; $this->params['aggregateMetricSpecId'] = 1; $resp = $this->_callJsonApi(); + /** @var array $notifications */ + $notifications = $resp->data; /** @var array $notifiedUsers */ - $notifiedUsers = $resp->data; + $notifiedUsers = $notifications[0]->users; /** @var array $expectedUserIds */ $expectedUserIds = array( 1 => false, @@ -433,16 +585,18 @@ public function testAggregatemetricspecNotificationEndpoints() $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifieduser.create'; $this->params['token'] = $token; $this->params['userId'] = 3; - $this->params['aggregateMetricSpecId'] = 1; + $this->params['aggregateMetricNotificationId'] = 1; $resp = $this->_callJsonApi(); $this->resetAll(); - $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifiedusers.list'; + $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifications.list'; $this->params['token'] = $token; $this->params['aggregateMetricSpecId'] = 1; $resp = $this->_callJsonApi(); + /** @var array $notifications */ + $notifications = $resp->data; /** @var array $notifiedUsers */ - $notifiedUsers = $resp->data; + $notifiedUsers = $notifications[0]->users; /** @var array $expectedUserIds */ $expectedUserIds = array( 1 => false, @@ -465,17 +619,19 @@ public function testAggregatemetricspecNotificationEndpoints() $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifieduser.delete'; $this->params['token'] = $token; $this->params['userId'] = 2; - $this->params['aggregateMetricSpecId'] = 1; + $this->params['aggregateMetricNotificationId'] = 1; $resp = $this->_callJsonApi(); $this->assertEquals(2, $resp->data->user_id); $this->resetAll(); - $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifiedusers.list'; + $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifications.list'; $this->params['token'] = $token; $this->params['aggregateMetricSpecId'] = 1; $resp = $this->_callJsonApi(); + /** @var array $notifications */ + $notifications = $resp->data; /** @var array $notifiedUsers */ - $notifiedUsers = $resp->data; + $notifiedUsers = $notifications[0]->users; /** @var array $expectedUserIds */ $expectedUserIds = array( 1 => false, @@ -498,17 +654,19 @@ public function testAggregatemetricspecNotificationEndpoints() $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifieduser.delete'; $this->params['token'] = $token; $this->params['userId'] = 1; - $this->params['aggregateMetricSpecId'] = 1; + $this->params['aggregateMetricNotificationId'] = 1; $resp = $this->_callJsonApi(); $this->assertEquals(1, $resp->data->user_id); $this->resetAll(); - $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifiedusers.list'; + $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifications.list'; $this->params['token'] = $token; $this->params['aggregateMetricSpecId'] = 1; $resp = $this->_callJsonApi(); + /** @var array $notifications */ + $notifications = $resp->data; /** @var array $notifiedUsers */ - $notifiedUsers = $resp->data; + $notifiedUsers = $notifications[0]->users; /** @var array $expectedUserIds */ $expectedUserIds = array( 3 => false, @@ -530,16 +688,18 @@ public function testAggregatemetricspecNotificationEndpoints() $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifieduser.delete'; $this->params['token'] = $token; $this->params['userId'] = 3; - $this->params['aggregateMetricSpecId'] = 1; + $this->params['aggregateMetricNotificationId'] = 1; $resp = $this->_callJsonApi(); $this->resetAll(); - $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifiedusers.list'; + $this->params['method'] = 'midas.tracker.aggregatemetricspecnotifications.list'; $this->params['token'] = $token; $this->params['aggregateMetricSpecId'] = 1; $resp = $this->_callJsonApi(); + /** @var array $notifications */ + $notifications = $resp->data; /** @var array $notifiedUsers */ - $notifiedUsers = $resp->data; + $notifiedUsers = $notifications[0]->users; $this->assertEquals(0, count($notifiedUsers)); } } diff --git a/modules/tracker/tests/controllers/ApiScalarComponentTest.php b/modules/tracker/tests/controllers/ApiScalarComponentTest.php deleted file mode 100644 index 19f3fee4d..000000000 --- a/modules/tracker/tests/controllers/ApiScalarComponentTest.php +++ /dev/null @@ -1,114 +0,0 @@ -enabledModules = array('api', 'scheduler', $this->moduleName); - $this->_models = array('Assetstore', 'Community', 'Setting', 'User'); - $this->setupDatabase(array('default')); - $this->setupDatabase(array('default'), 'tracker'); - - $db = Zend_Registry::get('dbAdapter'); - $configDatabase = Zend_Registry::get('configDatabase'); - if ($configDatabase->database->adapter == 'PDO_PGSQL') { - $db->query("SELECT setval('tracker_aggregate_metric_spec_aggregate_metric_spec_id_seq', (SELECT MAX(aggregate_metric_spec_id) FROM tracker_aggregate_metric_spec)+1);"); - $db->query("SELECT setval('tracker_scalar_scalar_id_seq', (SELECT MAX(scalar_id) FROM tracker_scalar)+1);"); - } - - ControllerTestCase::setUp(); - } - - /** - * Test updating an existing scalar with a set of params, via PUT. - * - * @throws Zend_Exception - */ - public function testPUT() - { - $usersFile = $this->loadData('User', 'default'); - /** @var UserDao $userDao */ - $userDao = $this->User->load($usersFile[0]->getKey()); - - // Create a scalar attached to a trend. - /** @var Tracker_TrendModel $trendModel */ - $trendModel = MidasLoader::loadModel('Trend', 'tracker'); - /** @var Tracker_TrendDao $trend */ - $trend = $trendModel->load(1001); - - /** @var Tracker_ScalarModel $scalarModel */ - $scalarModel = MidasLoader::loadModel('Scalar', 'tracker'); - $scalarArgs = array( - 'trend_id' => $trend->getTrendId(), - 'value' => 42, - 'build_results_url' => 'http://localhost', - ); - /** @var Tracker_ScalarDao $scalar */ - $scalar = $scalarModel->initDao('Scalar', $scalarArgs, $this->moduleName); - $scalarModel->save($scalar); - - $token = $this->_loginAsAdministrator(); - - $params = array( - 'num_param' => 90, - 'text_param' => 'master', - 'null_param' => '', - ); - $restParams = array( - 'trend_id' => $trend->getTrendId(), - 'params' => json_encode($params), - 'token' => $token, - ); - - $this->resetAll(); - $this->params = $restParams; - $resp = $this->_callRestApi('PUT', '/tracker/scalar/'.$scalar->getScalarId()); - - // Ensure params are properly set on scalar. - $paramChecks = array( - 'num_param' => array('found' => false, 'type' => 'numeric', 'val' => 90), - 'text_param' => array('found' => false, 'type' => 'text', 'val' => 'master'), - 'null_param' => array('found' => false, 'type' => 'text', 'val' => ''), - ); - - /** @var Tracker_ParamModel $param */ - foreach ($scalar->getParams() as $param) { - $checks = $paramChecks[$param->getParamName()]; - $this->assertEquals($checks['type'], $param->getParamType()); - if ($checks['type'] === 'numeric') { - $this->assertEquals($checks['val'], $param->getNumericValue()); - } else { - $this->assertEquals($checks['val'], $param->getTextValue()); - } - $paramChecks[$param->getParamName()]['found'] = true; - } - - foreach ($paramChecks as $checks) { - $this->assertTrue($checks['found']); - } - } -} diff --git a/modules/tracker/tests/controllers/CMakeLists.txt b/modules/tracker/tests/controllers/CMakeLists.txt index 72750b1d5..7f93fb2de 100644 --- a/modules/tracker/tests/controllers/CMakeLists.txt +++ b/modules/tracker/tests/controllers/CMakeLists.txt @@ -20,6 +20,6 @@ set(module_name tracker) to_titlecase(${module_name} module_name_titlecase) -add_midas_test(${module_name_titlecase}ApiComponent ApiComponentTest.php) -add_midas_test(${module_name_titlecase}ApiAggregatemetricspecComponent ApiAggregatemetricspecComponentTest.php) -add_midas_test(${module_name_titlecase}ApiScalarComponent ApiScalarComponentTest.php) +add_midas_mysql_test(${module_name_titlecase}ApiComponent ApiComponentTest.php) +add_midas_mysql_test(${module_name_titlecase}ApiAggregatemetricspecComponent ApiAggregatemetricspecComponentTest.php) +add_midas_mysql_test(${module_name_titlecase}ApiAggregatemetricnotificationComponent ApiAggregatemetricnotificationComponentTest.php) diff --git a/modules/tracker/tests/databaseDataset/aggregateMetric.xml b/modules/tracker/tests/databaseDataset/aggregateMetric.xml index 2154557f5..edb2ab8a3 100644 --- a/modules/tracker/tests/databaseDataset/aggregateMetric.xml +++ b/modules/tracker/tests/databaseDataset/aggregateMetric.xml @@ -2,265 +2,261 @@ + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + - + - - + + - - - - - + + + + + /> - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + diff --git a/modules/tracker/tests/databaseDataset/default.xml b/modules/tracker/tests/databaseDataset/default.xml index feb9d99b8..8236ad9f8 100644 --- a/modules/tracker/tests/databaseDataset/default.xml +++ b/modules/tracker/tests/databaseDataset/default.xml @@ -2,10 +2,9 @@ - - - + + + + diff --git a/modules/tracker/tests/models/base/AggregateMetricModelTest.php b/modules/tracker/tests/models/base/AggregateMetricModelTest.php index 4255d809e..1f7e7fbeb 100644 --- a/modules/tracker/tests/models/base/AggregateMetricModelTest.php +++ b/modules/tracker/tests/models/base/AggregateMetricModelTest.php @@ -27,24 +27,33 @@ public function setUp() $this->setupDatabase(array('default')); // core dataset $this->setupDatabase(array('aggregateMetric'), 'tracker'); // module dataset $this->enabledModules = array('tracker'); - $db = Zend_Registry::get('dbAdapter'); - $configDatabase = Zend_Registry::get('configDatabase'); - if ($configDatabase->database->adapter == 'PDO_PGSQL') { - $db->query("SELECT setval('tracker_aggregate_metric_spec_aggregate_metric_spec_id_seq', (SELECT MAX(aggregate_metric_spec_id) FROM tracker_aggregate_metric_spec)+1);"); - $db->query("SELECT setval('tracker_aggregate_metric_aggregate_metric_id_seq', (SELECT MAX(aggregate_metric_id) FROM tracker_aggregate_metric)+1);"); - $db->query("SELECT setval('tracker_trend_trend_id_seq', (SELECT MAX(trend_id) FROM tracker_trend)+1);"); - $db->query("SELECT setval('tracker_scalar_scalar_id_seq', (SELECT MAX(scalar_id) FROM tracker_scalar)+1);"); - } + parent::setUp(); } /** createAdditionalGreedyErrorSubmission1Scalars testing utility function. */ protected function createAdditionalGreedyErrorSubmission1Scalars() { + /** @var Tracker_ProducerModel $producerModel */ + $producerModel = MidasLoader::loadModel('Producer', 'tracker'); /** @var Tracker_TrendModel $trendModel */ $trendModel = MidasLoader::loadModel('Trend', 'tracker'); /** @var Tracker_ScalarModel $scalarModel */ $scalarModel = MidasLoader::loadModel('Scalar', 'tracker'); + /** @var Tracker_SubmissionModel $submissionModel */ + $submissionModel = MidasLoader::loadModel('Submission', 'tracker'); + + $producerDao = $producerModel->load(100); + + $submissionDao = $submissionModel->load(1); + $submissionDao->setSubmitTime(date('Y-m-d', time())); + $submissionDao->setProducerRevision(1); + + $submissionDao->setUserId(1); + $submissionDao->setOfficial((int) true); + $submissionDao->setBuildResultsUrl('build.results.url'); + $submissionDao->setBranch('master'); + $submissionModel->save($submissionDao); $extraTrends = array(); /** @var int $i */ @@ -55,15 +64,9 @@ protected function createAdditionalGreedyErrorSubmission1Scalars() $trendModel->save($trendDao); /** @var Tracker_ScalarDao $scalarDao */ $scalarDao = MidasLoader::newDao('ScalarDao', 'tracker'); - $scalarDao->setSubmissionId(1); + $scalarDao->setSubmissionId($submissionDao->getKey()); $scalarDao->setTrendId($trendDao->getKey()); - $scalarDao->setSubmitTime(date('Y-m-d', time())); - $scalarDao->setProducerRevision(1); $scalarDao->setValue(21.0 + $i); - $scalarDao->setUserId(1); - $scalarDao->setOfficial((int) true); - $scalarDao->setBuildResultsUrl('build.results.url'); - $scalarDao->setBranch('master'); $scalarModel->save($scalarDao); $extraTrends[] = $trendDao; } @@ -94,8 +97,6 @@ public function testGetAggregateMetricInputValuesForSubmission() /** @var AggregateMetricModel $aggregateMetricModel */ $aggregateMetricModel = MidasLoader::loadModel('AggregateMetric', 'tracker'); - /** @var Tracker_ProducerDao $producer100Dao */ - $producer100Dao = $producerModel->load(100); /** @var Tracker_SubmissionDao $submission1Dao */ $submission1Dao = $submissionModel->load(1); /** @var Tracker_SubmissionDao $submission2Dao */ @@ -319,24 +320,17 @@ public function testComputeAggregateMetricForSubmission() $aggregateMetricDao = $aggregateMetricModel->computeAggregateMetricForSubmission($optimalDistance55thPercentileAMSDao, $submission1Dao); $this->assertEquals($aggregateMetricDao, false); - // AMSes that match branch 'test', with only one scalar. - + // Submissions tied to branch 'test', with only one scalar. /** @var Tracker_SubmissionDao $submission8Dao */ $submission8Dao = $submissionModel->load(8); - /** @var Tracker_AggregateMetricSpecDao $greedyErrorTest0thPercentileAMSDao */ - $greedyErrorTest0thPercentileAMSDao = $aggregateMetricSpecModel->load(8); - $aggregateMetricDao = $aggregateMetricModel->computeAggregateMetricForSubmission($greedyErrorTest0thPercentileAMSDao, $submission8Dao); + $aggregateMetricDao = $aggregateMetricModel->computeAggregateMetricForSubmission($greedyError0thPercentileAMSDao, $submission8Dao); $this->assertEquals($aggregateMetricDao->getValue(), 654.0); - /** @var Tracker_AggregateMetricSpecDao $greedyErrorTest55thPercentileAMSDao */ - $greedyErrorTest55thPercentileAMSDao = $aggregateMetricSpecModel->load(9); - $aggregateMetricDao = $aggregateMetricModel->computeAggregateMetricForSubmission($greedyErrorTest55thPercentileAMSDao, $submission8Dao); + $aggregateMetricDao = $aggregateMetricModel->computeAggregateMetricForSubmission($greedyError55thPercentileAMSDao, $submission8Dao); $this->assertEquals($aggregateMetricDao->getValue(), 654.0); - /** @var Tracker_AggregateMetricSpecDao $greedyErrorTest99thPercentileAMSDao */ - $greedyErrorTest99thPercentileAMSDao = $aggregateMetricSpecModel->load(10); - $aggregateMetricDao = $aggregateMetricModel->computeAggregateMetricForSubmission($greedyErrorTest99thPercentileAMSDao, $submission8Dao); + $aggregateMetricDao = $aggregateMetricModel->computeAggregateMetricForSubmission($greedyError95thPercentileAMSDao, $submission8Dao); $this->assertEquals($aggregateMetricDao->getValue(), 654.0); // AMS that doesn't match any trends. @@ -347,13 +341,6 @@ public function testComputeAggregateMetricForSubmission() $aggregateMetricDao = $aggregateMetricModel->computeAggregateMetricForSubmission($noopDistance95thPercentileAMSDao, $submission1Dao); $this->assertEquals($aggregateMetricDao, false); - // AMS that doesn't match any branches. - /** @var Tracker_AggregateMetricSpecDao $noopDistance95thPercentileTestAMSDao */ - $branch = 'test'; - $noopDistance95thPercentileTestAMSDao = $aggregateMetricSpecModel->createAggregateMetricSpec($producer100Dao, $name, $spec, $branch); - $aggregateMetricDao = $aggregateMetricModel->computeAggregateMetricForSubmission($noopDistance95thPercentileTestAMSDao, $submission1Dao); - $this->assertEquals($aggregateMetricDao, false); - // AMS with missing percentile param. /** @var Tracker_AggregateMetricSpecDao $greedyErrorMissingPercentileAMSDao */ $name = 'Percentile Greedy error'; @@ -481,13 +468,6 @@ public function testUpdateAggregateMetricForSubmission() $aggregateMetricDao = $aggregateMetricModel->updateAggregateMetricForSubmission($noopDistance95thPercentileAMSDao, $submission1Dao); $this->assertEquals($aggregateMetricDao, false); - // AMS that doesn't match any branches. - /** @var Tracker_AggregateMetricSpecDao $noopDistance95thPercentileTestAMSDao */ - $branch = 'test'; - $noopDistance95thPercentileTestAMSDao = $aggregateMetricSpecModel->createAggregateMetricSpec($producer100Dao, $name, $spec, $branch); - $aggregateMetricDao = $aggregateMetricModel->updateAggregateMetricForSubmission($noopDistance95thPercentileTestAMSDao, $submission1Dao); - $this->assertEquals($aggregateMetricDao, false); - // AMS with missing percentile param. /** @var Tracker_AggregateMetricSpecDao $greedyErrorMissingPercentileAMSDao */ $name = 'Percentile Greedy error'; diff --git a/modules/tracker/tests/models/base/AggregateMetricNotificationModelTest.php b/modules/tracker/tests/models/base/AggregateMetricNotificationModelTest.php new file mode 100644 index 000000000..d3188ec0f --- /dev/null +++ b/modules/tracker/tests/models/base/AggregateMetricNotificationModelTest.php @@ -0,0 +1,268 @@ +setupDatabase(array('default')); // core dataset + $this->setupDatabase(array('aggregateMetric'), 'tracker'); // module dataset + $this->enabledModules = array('scheduler', 'tracker'); + $this->_components = array('Json'); + + parent::setUp(); + } + + /** tearDown tester method. */ + public function tearDown() + { + // Delete notified users. + $db = Zend_Registry::get('dbAdapter'); + $db->delete('scheduler_job', "task = 'TASK_TRACKER_SEND_AGGREGATE_METRIC_NOTIFICATION'"); + parent::tearDown(); + } + + /** testUserNotifications */ + public function testUserNotifications() + { + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', 'tracker'); + + /** @var Tracker_AggregateMetricNotificationDao $amn95thPercentileGreedyError */ + $amn95thPercentileGreedyError = $aggregateMetricNotificationModel->load(1); + /** @var Tracker_AggregateMetricNotificationDao $amn55thPercentileGreedyError */ + $amn55thPercentileGreedyError = $aggregateMetricNotificationModel->load(2); + + // At first there are no notified users. + $this->assertEquals(0, count($aggregateMetricNotificationModel->getAllNotifiedUsers($amn95thPercentileGreedyError))); + $this->assertEquals(0, count($aggregateMetricNotificationModel->getAllNotifiedUsers($amn55thPercentileGreedyError))); + + /** @var UserModel $userModel */ + $userModel = MidasLoader::loadModel('User'); + /** @var UserDao $user1Dao */ + $user1Dao = $userModel->load(1); + /** @var UserDao $user2Dao */ + $user2Dao = $userModel->load(2); + /** @var UserDao $user3Dao */ + $user3Dao = $userModel->load(3); + + // Add users to 95th percentile greedy error AMS. + + $expectedNotifiedUsers95thGreedyError = array( + $user1Dao->getUserId() => false, + $user2Dao->getUserId() => false, + ); + + $aggregateMetricNotificationModel->createUserNotification($amn95thPercentileGreedyError, $user1Dao); + $aggregateMetricNotificationModel->createUserNotification($amn95thPercentileGreedyError, $user2Dao); + + $actualNotifiedUsers95thGreedyError = $aggregateMetricNotificationModel->getAllNotifiedUsers($amn95thPercentileGreedyError); + $this->assertEquals(count($expectedNotifiedUsers95thGreedyError), count($actualNotifiedUsers95thGreedyError)); + /** @var $UserDao $notifiedUser */ + foreach ($actualNotifiedUsers95thGreedyError as $notifiedUser) { + $expectedNotifiedUsers95thGreedyError[$notifiedUser->getUserId()] = true; + } + // Ensure that the users tied to the notification are who we expect. + /** @var $UserDao $expectedUser */ + /** @var bool $present */ + foreach ($expectedNotifiedUsers95thGreedyError as $notifiedUser => $present) { + $this->assertTrue($present); + } + + // Add a different set of users to 55th percentile greedy error AMS. + + $expectedNotifiedUsers55thGreedyError = array( + $user1Dao->getUserId() => false, + $user3Dao->getUserId() => false, + ); + + $aggregateMetricNotificationModel->createUserNotification($amn55thPercentileGreedyError, $user1Dao); + $aggregateMetricNotificationModel->createUserNotification($amn55thPercentileGreedyError, $user3Dao); + + $actualNotifiedUsers55thGreedyError = $aggregateMetricNotificationModel->getAllNotifiedUsers($amn55thPercentileGreedyError); + $this->assertEquals(count($expectedNotifiedUsers55thGreedyError), count($actualNotifiedUsers55thGreedyError)); + /** @var $UserDao $notifiedUser */ + foreach ($actualNotifiedUsers55thGreedyError as $notifiedUser) { + $expectedNotifiedUsers55thGreedyError[$notifiedUser->getUserId()] = true; + } + // Ensure that the users tied to the notification are who we expect. + /** @var $UserDao $expectedUser */ + /** @var bool $present */ + foreach ($expectedNotifiedUsers55thGreedyError as $notifiedUser => $present) { + $this->assertTrue($present); + } + + // Test that scheduler jobs are created for notifications. + + /** @var Tracker_AggregateMetricSpecModel $aggregateMetricSpecModel */ + $aggregateMetricSpecModel = MidasLoader::loadModel('AggregateMetricSpec', 'tracker'); + /** @var Tracker_AggregateMetricSpecDao $greedyError95thPercentileAMSDao */ + $greedyError95thPercentileAMSDao = $aggregateMetricSpecModel->load(1); + /** @var Tracker_AggregateMetricSpecDao $greedyError55thPercentileAMSDao */ + $greedyError55thPercentileAMSDao = $aggregateMetricSpecModel->load(2); + + /** @var Tracker_SubmissionModel $submissionModel */ + $submissionModel = MidasLoader::loadModel('Submission', 'tracker'); + + // Submissions 1 and 2 are tied to branch 'master', submission 8 to 'test'. + // Metrics should be calculated regardless of branch. + // Notifications are tied to branches. + + /** @var Tracker_SubmissionDao $submission1Dao */ + $submission1Dao = $submissionModel->load(1); + /** @var Tracker_SubmissionDao $submission2Dao */ + $submission2Dao = $submissionModel->load(2); + /** @var Tracker_SubmissionDao $submission8Dao */ + $submission8Dao = $submissionModel->load(8); + + /** @var Tracker_AggregateMetricModel $aggregateMetricModel */ + $aggregateMetricModel = MidasLoader::loadModel('AggregateMetric', 'tracker'); + + // Sadly, enabling a module does not import its constants. + require_once BASE_PATH.'/modules/scheduler/constant/module.php'; + /** @var Scheduler_JobModel $jobModel */ + $jobModel = MidasLoader::loadModel('Job', 'scheduler'); + // Ensure there aren't any notification jobs existing. + $this->assertEquals(0, count($jobModel->findBy('task', 'TASK_TRACKER_SEND_AGGREGATE_METRIC_NOTIFICATION'))); + + /** @var Tracker_AggregateMetricDao $greedyError95thSubmission1Metric */ + $greedyError95thSubmission1Metric = $aggregateMetricModel->updateAggregateMetricForSubmission($greedyError95thPercentileAMSDao, $submission1Dao); + $this->assertEquals($greedyError95thSubmission1Metric->getValue(), 19.0); + $notificationJobs = $aggregateMetricNotificationModel->scheduleNotificationJobs($greedyError95thSubmission1Metric); + $this->assertEquals(0, count($notificationJobs)); + + $expectedNotifiedUsers95thGreedyError = array( + $user1Dao->getUserId() => false, + $user2Dao->getUserId() => false, + ); + + /** @var Tracker_AggregateMetricDao $greedyError95thSubmission2Metric */ + $greedyError95thSubmission2Metric = $aggregateMetricModel->updateAggregateMetricForSubmission($greedyError95thPercentileAMSDao, $submission2Dao); + $this->assertEquals($greedyError95thSubmission2Metric->getValue(), 38.0); + $notificationJobs = $aggregateMetricNotificationModel->scheduleNotificationJobs($greedyError95thSubmission2Metric); + $this->assertEquals(2, count($notificationJobs)); + foreach ($notificationJobs as $job) { + preg_match("/\"recipient_id\":\"(\d+)\"/", $job->getParams(), $matches); + $userId = $matches[1]; + $expectedNotifiedUsers95thGreedyError[$userId] = true; + } + // Ensure notifications are created for the correct users. + /** @var $UserDao $notifiedUser */ + /** @var bool $present */ + foreach ($expectedNotifiedUsers95thGreedyError as $notifiedUser => $present) { + $this->assertTrue($present); + } + + /** @var Tracker_AggregateMetricDao $greedyError95thSubmission8Metric */ + $greedyError95thSubmission8Metric = $aggregateMetricModel->updateAggregateMetricForSubmission($greedyError95thPercentileAMSDao, $submission8Dao); + $this->assertEquals($greedyError95thSubmission8Metric->getValue(), 654.0); + // Even though the value is above threshold, it is not a branch that will notify. + $this->assertEquals(0, count($aggregateMetricNotificationModel->scheduleNotificationJobs($greedyError95thSubmission8Metric))); + + /** @var Tracker_AggregateMetricDao $greedyError55thSubmission1Metric */ + $greedyError55thSubmission1Metric = $aggregateMetricModel->updateAggregateMetricForSubmission($greedyError55thPercentileAMSDao, $submission1Dao); + $this->assertEquals($greedyError55thSubmission1Metric->getValue(), 11.0); + $this->assertEquals(0, count($aggregateMetricNotificationModel->scheduleNotificationJobs($greedyError55thSubmission1Metric))); + + $expectedNotifiedUsers55thGreedyError = array( + $user1Dao->getUserId() => false, + $user3Dao->getUserId() => false, + ); + + /** @var Tracker_AggregateMetricDao $greedyError55thSubmission2Metric */ + $greedyError55thSubmission2Metric = $aggregateMetricModel->updateAggregateMetricForSubmission($greedyError55thPercentileAMSDao, $submission2Dao); + $this->assertEquals($greedyError55thSubmission2Metric->getValue(), 22.0); + $notificationJobs = $aggregateMetricNotificationModel->scheduleNotificationJobs($greedyError55thSubmission2Metric); + $this->assertEquals(2, count($notificationJobs)); + foreach ($notificationJobs as $job) { + preg_match("/\"recipient_id\":\"(\d+)\"/", $job->getParams(), $matches); + $userId = $matches[1]; + $expectedNotifiedUsers55thGreedyError[$userId] = true; + } + // Ensure notifications are created for the correct users. + /** @var $UserDao $notifiedUser */ + /** @var bool $present */ + foreach ($expectedNotifiedUsers55thGreedyError as $notifiedUser => $present) { + $this->assertTrue($present); + } + + /** @var Tracker_AggregateMetricDao $greedyError55thSubmission8Metric */ + $greedyError55thSubmission8Metric = $aggregateMetricModel->computeAggregateMetricForSubmission($greedyError55thPercentileAMSDao, $submission8Dao); + $this->assertEquals($greedyError55thSubmission8Metric->getValue(), 654.0); + // Even though the value is above threshold, it is not a branch that will notify. + $this->assertEquals(0, count($aggregateMetricNotificationModel->scheduleNotificationJobs($greedyError55thSubmission8Metric))); + + // Clean up after the test. + $aggregateMetricModel->delete($greedyError95thSubmission1Metric); + $aggregateMetricModel->delete($greedyError55thSubmission1Metric); + + // Ensure that removing a user from a notification actually removes them. + $aggregateMetricNotificationModel->deleteUserNotification($amn95thPercentileGreedyError, $user1Dao); + $aggregateMetricNotificationModel->deleteUserNotification($amn95thPercentileGreedyError, $user2Dao); + $actualNotifiedUsers95thGreedyError = $aggregateMetricNotificationModel->getAllNotifiedUsers($amn95thPercentileGreedyError); + $this->assertEquals(0, count($actualNotifiedUsers95thGreedyError)); + + // Ensure that removing a user from a notification actually removes them. + $aggregateMetricNotificationModel->deleteUserNotification($amn55thPercentileGreedyError, $user1Dao); + $aggregateMetricNotificationModel->deleteUserNotification($amn55thPercentileGreedyError, $user3Dao); + $actualNotifiedUsers55thGreedyError = $aggregateMetricNotificationModel->getAllNotifiedUsers($amn55thPercentileGreedyError); + $this->assertEquals(0, count($actualNotifiedUsers55thGreedyError)); + } + + /** testDelete */ + public function testDelete() + { + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', 'tracker'); + + // Create a notification, tie 2 users to it, then delete it. + $args = array( + 'aggregate_metric_spec_id' => 1, + 'branch' => 'blaster', + 'comparison' => '>', + 'value' => 1, + ); + + /** @var Tracker_AggregateMetricNotificationDao $aggregateMetricNotificationDao */ + $aggregateMetricNotificationDao = $aggregateMetricNotificationModel->initDao('AggregateMetricNotification', $args, 'tracker'); + $aggregateMetricNotificationModel->save($aggregateMetricNotificationDao); + $amnId = $aggregateMetricNotificationDao->getAggregateMetricNotificationId(); + + /** @var UserModel $userModel */ + $userModel = MidasLoader::loadModel('User'); + /** @var UserDao $user1Dao */ + $user1Dao = $userModel->load(1); + /** @var UserDao $user2Dao */ + $user2Dao = $userModel->load(2); + + $aggregateMetricNotificationModel->createUserNotification($aggregateMetricNotificationDao, $user1Dao); + $aggregateMetricNotificationModel->createUserNotification($aggregateMetricNotificationDao, $user2Dao); + + $aggregateMetricNotificationModel->delete($aggregateMetricNotificationDao); + + // Ensure the linked users are deleted. + $db = Zend_Registry::get('dbAdapter'); + $row = $db->query('select count(*) as count from tracker_user2aggregate_metric_notification where aggregate_metric_notification_id = '.$amnId)->fetch(); + $this->assertEquals($row['count'], 0); + $this->assertFalse($aggregateMetricNotificationModel->load($amnId)); + } +} diff --git a/modules/tracker/tests/models/base/AggregateMetricSpecModelTest.php b/modules/tracker/tests/models/base/AggregateMetricSpecModelTest.php index 6f2b78e61..7b0a50235 100644 --- a/modules/tracker/tests/models/base/AggregateMetricSpecModelTest.php +++ b/modules/tracker/tests/models/base/AggregateMetricSpecModelTest.php @@ -21,18 +21,14 @@ /** Test the AggregateMetricSpec. */ class Tracker_AggregateMetricSpecModelTest extends DatabaseTestCase { + public $moduleName = 'tracker'; + /** Set up tests. */ public function setUp() { $this->setupDatabase(array('default')); // core dataset $this->setupDatabase(array('aggregateMetric'), 'tracker'); // module dataset $this->enabledModules = array('tracker'); - $db = Zend_Registry::get('dbAdapter'); - $configDatabase = Zend_Registry::get('configDatabase'); - if ($configDatabase->database->adapter == 'PDO_PGSQL') { - $db->query("SELECT setval('tracker_aggregate_metric_spec_aggregate_metric_spec_id_seq', (SELECT MAX(aggregate_metric_spec_id) FROM tracker_aggregate_metric_spec)+1);"); - $db->query("SELECT setval('tracker_aggregate_metric_aggregate_metric_id_seq', (SELECT MAX(aggregate_metric_id) FROM tracker_aggregate_metric)+1);"); - } parent::setUp(); } @@ -162,62 +158,6 @@ public function testGetAggregateMetricSpecsForSubmission() $this->assertFalse($submissionAggregateMetricSpecDaos); } - /** test AggregateMetricSpecModel notification related functions */ - public function testAggregateMetricSpecNotificationFunctions() - { - /** @var AggregateMetricSpecModel $aggregateMetricSpecModel */ - $aggregateMetricSpecModel = MidasLoader::loadModel('AggregateMetricSpec', 'tracker'); - - $name = '67th Percentile Greedy distance '; - $spec = "percentile('Greedy distance', 67)"; - - /** @var Tracker_ProducerModel $producerModel */ - $producerModel = MidasLoader::loadModel('Producer', 'tracker'); - /** @var Tracker_ProducerDao $producer100Dao */ - $producer100Dao = $producerModel->load(100); - - /** @var AggregateMetricSpecDao $validAMSDao */ - $validAMSDao = $aggregateMetricSpecModel->createAggregateMetricSpec($producer100Dao, $name, $spec); - - // There should be no notifications. - $this->assertEquals(0, count($aggregateMetricSpecModel->getAllNotifiedUsers($validAMSDao))); - - /** @var UserModel $userModel */ - $userModel = MidasLoader::loadModel('User'); - /** @var UserDao $user1Dao */ - $user1Dao = $userModel->load(1); - /** @var UserDao $user2Dao */ - $user2Dao = $userModel->load(2); - /** @var UserDao $user3Dao */ - $user3Dao = $userModel->load(3); - - // Create 3 notifications. - $aggregateMetricSpecModel->createUserNotification($validAMSDao, $user1Dao); - // Try to repeat a creation, should not fail. - $aggregateMetricSpecModel->createUserNotification($validAMSDao, $user1Dao); - $aggregateMetricSpecModel->createUserNotification($validAMSDao, $user2Dao); - $aggregateMetricSpecModel->createUserNotification($validAMSDao, $user3Dao); - - $this->assertEquals(3, count($aggregateMetricSpecModel->getAllNotifiedUsers($validAMSDao))); - - // Delete and check. - $aggregateMetricSpecModel->deleteUserNotification($validAMSDao, $user3Dao); - $this->assertEquals(2, count($aggregateMetricSpecModel->getAllNotifiedUsers($validAMSDao))); - - $aggregateMetricSpecModel->deleteUserNotification($validAMSDao, $user1Dao); - /** @var array $notifications */ - $notifications = $aggregateMetricSpecModel->getAllNotifiedUsers($validAMSDao); - $this->assertEquals(1, count($notifications)); - // Deleted 1 and 3, 2 should be left. - $this->assertEquals($notifications[0]->user_id, 2); - - $aggregateMetricSpecModel->deleteUserNotification($validAMSDao, $user2Dao); - $this->assertEquals(0, count($aggregateMetricSpecModel->getAllNotifiedUsers($validAMSDao))); - - // Clean up the created spec. - $aggregateMetricSpecModel->delete($validAMSDao); - } - /** test AggregateMetricSpecModel delete function */ public function testAggregateMetricSpecDelete() { @@ -256,8 +196,7 @@ public function testAggregateMetricSpecDelete() /** @var AggregateMetricSpecDao $validAMSDao */ $validAMSDao = $aggregateMetricSpecModel->createAggregateMetricSpec($producer100Dao, $name, $spec); - // There should be no notifications. - $this->assertEquals(0, count($aggregateMetricSpecModel->getAllNotifiedUsers($validAMSDao))); + // Create A notification, tied to 2 users. /** @var UserModel $userModel */ $userModel = MidasLoader::loadModel('User'); @@ -265,15 +204,28 @@ public function testAggregateMetricSpecDelete() $user1Dao = $userModel->load(1); /** @var UserDao $user2Dao */ $user2Dao = $userModel->load(2); - /** @var UserDao $user3Dao */ - $user3Dao = $userModel->load(3); - // Create 3 notifications. - $aggregateMetricSpecModel->createUserNotification($validAMSDao, $user1Dao); - $aggregateMetricSpecModel->createUserNotification($validAMSDao, $user2Dao); - $aggregateMetricSpecModel->createUserNotification($validAMSDao, $user3Dao); + /** @var Tracker_AggregateMetricNotificationModel $aggregateMetricNotificationModel */ + $aggregateMetricNotificationModel = MidasLoader::loadModel('AggregateMetricNotification', 'tracker'); + + $notificationProperties = array( + 'aggregate_metric_spec_id' => $validAMSDao->getAggregateMetricSpecId(), + 'branch' => 'notify 1', + 'comparison' => '==', + 'value' => '16.0', + ); + /** @var Tracker_AggregateMetricNotificationDao $notification1Dao */ + $notification1Dao = $aggregateMetricNotificationModel->initDao('AggregateMetricNotification', $notificationProperties, $this->moduleName); + $aggregateMetricNotificationModel->save($notification1Dao); + $aggregateMetricNotificationModel->createUserNotification($notification1Dao, $user1Dao); + $aggregateMetricNotificationModel->createUserNotification($notification1Dao, $user2Dao); + + $this->assertEquals(2, count($aggregateMetricNotificationModel->getAllNotifiedUsers($notification1Dao))); - $this->assertEquals(3, count($aggregateMetricSpecModel->getAllNotifiedUsers($validAMSDao))); + /** @var AggregateMetricSpecDao $cachedAMSDao */ + $cachedAMSDao = $aggregateMetricSpecModel->load($validAMSDao->getAggregateMetricSpecId()); + + // Compute some aggregate metrics to check that they will be deleted. /** @var AggregateMetricModel $aggregateMetricModel */ $aggregateMetricModel = MidasLoader::loadModel('AggregateMetric', 'tracker'); @@ -285,27 +237,31 @@ public function testAggregateMetricSpecDelete() $aggregateMetricDaos = $aggregateMetricModel->getAggregateMetricsForSubmission($submission1Dao); $this->assertEquals(1, count($aggregateMetricDaos)); $this->assertEquals($aggregateMetricDaos[0]->getValue(), 7.0); - $aggregateMetricDao = $aggregateMetricModel->updateAggregateMetricForSubmission($validAMSDao, $submission2Dao); $this->assertEquals($aggregateMetricDao->getValue(), 14.0); $aggregateMetricDaos = $aggregateMetricModel->getAggregateMetricsForSubmission($submission2Dao); $this->assertEquals(1, count($aggregateMetricDaos)); $this->assertEquals($aggregateMetricDaos[0]->getValue(), 14.0); - // Delete the created spec. /** @var AggregateMetricSpecDao $cachedAMSDao */ $cachedAMSDao = $aggregateMetricSpecModel->load($validAMSDao->getAggregateMetricSpecId()); + + // Delete the created spec, which should cascade to the metrics, the notifications, and the notification users. $aggregateMetricSpecModel->delete($validAMSDao); $aggregateMetricDaos = $aggregateMetricModel->getAggregateMetricsForSubmission($submission1Dao); $this->assertEquals(0, count($aggregateMetricDaos)); $aggregateMetricDaos = $aggregateMetricModel->getAggregateMetricsForSubmission($submission2Dao); $this->assertEquals(0, count($aggregateMetricDaos)); - // The AMS is deleted in the DB, but we have cached a DAO so we can ensure there are no notifications. - $this->assertEquals(0, count($aggregateMetricSpecModel->getAllNotifiedUsers($cachedAMSDao))); /** @var AggregateMetricSpecDao $loadedAMSDao */ $loadedAMSDao = $aggregateMetricSpecModel->load($cachedAMSDao->getAggregateMetricSpecId()); $this->assertFalse($loadedAMSDao); + + // There shouldn't be any linked users. + $this->assertEquals(0, count($aggregateMetricNotificationModel->getAllNotifiedUsers($notification1Dao))); + // Reloading the notification DAO should produce false. + $notification1Dao = $aggregateMetricNotificationModel->load($notification1Dao->getAggregateMetricNotificationId()); + $this->assertFalse($notification1Dao); } } diff --git a/modules/tracker/tests/models/base/CMakeLists.txt b/modules/tracker/tests/models/base/CMakeLists.txt index bfad46de1..db0d926a7 100644 --- a/modules/tracker/tests/models/base/CMakeLists.txt +++ b/modules/tracker/tests/models/base/CMakeLists.txt @@ -20,7 +20,8 @@ set(module_name tracker) to_titlecase(${module_name} module_name_titlecase) -add_midas_test(${module_name_titlecase}AggregateMetricModel AggregateMetricModelTest.php) -add_midas_test(${module_name_titlecase}AggregateMetricSpecModel AggregateMetricSpecModelTest.php) -add_midas_test(${module_name_titlecase}ScalarModel ScalarModelTest.php) -add_midas_test(${module_name_titlecase}TrendModel TrendModelTest.php) +add_midas_mysql_test(${module_name_titlecase}AggregateMetricModel AggregateMetricModelTest.php) +add_midas_mysql_test(${module_name_titlecase}AggregateMetricNotificationModel AggregateMetricNotificationModelTest.php) +add_midas_mysql_test(${module_name_titlecase}AggregateMetricSpecModel AggregateMetricSpecModelTest.php) +add_midas_mysql_test(${module_name_titlecase}ScalarModel ScalarModelTest.php) +add_midas_mysql_test(${module_name_titlecase}SubmissionModel SubmissionModelTest.php) diff --git a/modules/tracker/tests/models/base/ScalarModelTest.php b/modules/tracker/tests/models/base/ScalarModelTest.php index ec8e4e829..49063fdc5 100644 --- a/modules/tracker/tests/models/base/ScalarModelTest.php +++ b/modules/tracker/tests/models/base/ScalarModelTest.php @@ -27,12 +27,7 @@ public function setUp() $this->setupDatabase(array('default')); // core dataset $this->setupDatabase(array('default'), 'tracker'); // module dataset $this->enabledModules = array('tracker'); - $db = Zend_Registry::get('dbAdapter'); - $configDatabase = Zend_Registry::get('configDatabase'); - if ($configDatabase->database->adapter == 'PDO_PGSQL') { - $db->query("SELECT setval('tracker_submission_submission_id_seq', (SELECT MAX(submission_id) FROM tracker_submission)+1);"); - $db->query("SELECT setval('tracker_scalar_scalar_id_seq', (SELECT MAX(scalar_id) FROM tracker_scalar)+1);"); - } + parent::setUp(); } @@ -42,10 +37,6 @@ public function testScalarModel() /** @var UuidComponent $uuidComponent */ $uuidComponent = MidasLoader::loadComponent('Uuid'); - $communityId = '2000'; - $producerDisplayName = 'Test Producer'; - $producerRevision = 'deadbeef'; - $submitTime = 'now'; $submissionUuid = $uuidComponent->generate(); /** @var UserModel $userModel */ @@ -83,109 +74,24 @@ public function testScalarModel() /** @var Tracker_ScalarDao $scalarDao0 */ $scalarDao0 = $scalarModel->addToTrend( $metricTrend0, - $submitTime, - $submissionId, - $producerRevision, - $scalarValue0, - $userDao, - true, - true, - 'http://buildresultsurl', - 'master', - $params0); - - // Ensure value and params are properly set on scalar. - $paramChecks = array( - 'num_param' => array('found' => false, 'type' => 'numeric', 'val' => 90), - 'text_param' => array('found' => false, 'type' => 'text', 'val' => 'master'), - 'emptystring_param' => array('found' => false, 'type' => 'text', 'val' => ''), - 'null_param' => array('found' => false, 'type' => 'text', 'val' => ''), + $submissionDao, + $scalarValue0 ); - $scalarDao0Params = $scalarDao0->getParams(); - foreach ($scalarDao0Params as $param) { - $checks = $paramChecks[$param->getParamName()]; - $this->assertEquals($checks['type'], $param->getParamType()); - if ($checks['type'] === 'numeric') { - $this->assertEquals($checks['val'], $param->getNumericValue()); - } else { - $this->assertEquals($checks['val'], $param->getTextValue()); - } - $paramChecks[$param->getParamName()]['found'] = true; - } - - foreach ($paramChecks as $checks) { - $this->assertTrue($checks['found']); - } - $this->assertEquals($scalarDao0->getValue(), $scalarValue0); // Scalar the second. /** @var Tracker_TrendDao $metricTrend1 */ $metricTrend1 = $trendModel->load(1002); $scalarValue1 = 1; - $params1 = array( - 'num_param' => 92, - 'text_param' => 'dev', - 'null_param' => null, - 'emptystring_param' => '', - ); + /** @var Tracker_ScalarDao $scalarDao1 */ $scalarDao1 = $scalarModel->addToTrend( $metricTrend1, - $submitTime, - $submissionId, - $producerRevision, - $scalarValue1, - $userDao, - true, - true, - 'http://buildresultsurl', - 'dev', - $params1); - - // Ensure value and params are properly set on scalar. - $paramChecks = array( - 'num_param' => array('found' => false, 'type' => 'numeric', 'val' => 92), - 'text_param' => array('found' => false, 'type' => 'text', 'val' => 'dev'), - 'emptystring_param' => array('found' => false, 'type' => 'text', 'val' => ''), - 'null_param' => array('found' => false, 'type' => 'text', 'val' => ''), + $submissionDao, + $scalarValue1 ); - $scalarDao1Params = $scalarDao1->getParams(); - /** @var Tracker_ParamModel $param */ - foreach ($scalarDao1Params as $param) { - $checks = $paramChecks[$param->getParamName()]; - $this->assertEquals($checks['type'], $param->getParamType()); - if ($checks['type'] === 'numeric') { - $this->assertEquals($checks['val'], $param->getNumericValue()); - } else { - $this->assertEquals($checks['val'], $param->getTextValue()); - } - $paramChecks[$param->getParamName()]['found'] = true; - } - - foreach ($paramChecks as $checks) { - $this->assertTrue($checks['found']); - } - $this->assertEquals($scalarDao1->getValue(), $scalarValue1); - - // Delete scalars and ensure params are deleted. - $scalarModel->delete($scalarDao0); - $scalarModel->delete($scalarDao1); - - /** @var Tracker_ParamModel $paramModel */ - $paramModel = MidasLoader::loadModel('Param', 'tracker'); - /** @var Tracker_ParamModel $scalarParam */ - foreach ($scalarDao0Params as $scalarParam) { - $scalarParamReloaded = $paramModel->load($scalarParam->getParamId()); - $this->assertFalse($scalarParamReloaded, 'Scalar param should have been deleted'); - } - /** @var Tracker_ParamModel $scalarParam */ - foreach ($scalarDao1Params as $scalarParam) { - $scalarParamReloaded = $paramModel->load($scalarParam->getParamId()); - $this->assertFalse($scalarParamReloaded, 'Scalar param should have been deleted'); - } } } diff --git a/modules/tracker/tests/models/base/SubmissionModelTest.php b/modules/tracker/tests/models/base/SubmissionModelTest.php new file mode 100644 index 000000000..00a03bf3b --- /dev/null +++ b/modules/tracker/tests/models/base/SubmissionModelTest.php @@ -0,0 +1,154 @@ +setupDatabase(array('default')); // core dataset + $this->setupDatabase(array('default'), 'tracker'); // module dataset + $this->enabledModules = array('tracker'); + + parent::setUp(); + } + + /** testScalarModel */ + public function testSubmissionModel() + { + /** @var Tracker_ParamModel $paramModel */ + $paramModel = MidasLoader::loadModel('Param', 'tracker'); + + /** @var Tracker_SubmissionModel $submissionModel */ + $submissionModel = MidasLoader::loadModel('Submission', 'tracker'); + + /** @var Tracker_ProducerModel $producerModel */ + $producerModel = MidasLoader::loadModel('Producer', 'tracker'); + + /** @var UuidComponent $uuidComponent */ + $uuidComponent = MidasLoader::loadComponent('Uuid'); + + /** @var UserModel $userModel */ + $userModel = MidasLoader::loadModel('User'); + $usersFile = $this->loadData('User', 'default'); + /** @var UserDao $userDao */ + $userDao = $userModel->load($usersFile[0]->getKey()); + + /** @var Tracker_ProducerDao $producerDao */ + $producerDao = $producerModel->load(100); + + $producerRevision = 'deadbeef'; + $uuid0 = $uuidComponent->generate(); + $uuid1 = $uuidComponent->generate(); + + $params0 = array( + 'num_param_subtest' => 90, + 'text_param_subtest' => 'master', + 'emptystring_param_subtest' => '', + 'null_param_subtest' => null, + ); + /** @var Tracker_SubmissionDao $submissionDao0 */ + $submissionDao0 = $submissionModel->createSubmission($producerDao, $uuid0, '', $params0); + $submissionDao0->setProducerRevision($producerRevision); + $submissionDao0->setUserId($userDao->getKey()); + $submissionDao0->setBuildResultsUrl('http://buildresultsurl'); + $submissionDao0->setBranch('master'); + $submissionModel->save($submissionDao0); + + // Ensure value and params are properly set on scalar. + $paramChecks = array( + 'num_param_subtest' => array('found' => false, 'type' => 'numeric', 'val' => 90), + 'text_param_subtest' => array('found' => false, 'type' => 'text', 'val' => 'master'), + 'emptystring_param_subtest' => array('found' => false, 'type' => 'text', 'val' => ''), + 'null_param_subtest' => array('found' => false, 'type' => 'text', 'val' => ''), + ); + + $submissionDao0Params = $submissionDao0->getParams(); + foreach ($submissionDao0Params as $param) { + $checks = $paramChecks[$param->getParamName()]; + $this->assertEquals($checks['type'], $param->getParamType()); + if ($checks['type'] === 'numeric') { + $this->assertEquals($checks['val'], $param->getNumericValue()); + } else { + $this->assertEquals($checks['val'], $param->getTextValue()); + } + $paramChecks[$param->getParamName()]['found'] = true; + } + + foreach ($paramChecks as $checks) { + $this->assertTrue($checks['found']); + } + + $params1 = array( + 'num_param_subtest' => 92, + 'text_param_subtest' => 'dev', + 'null_param_subtest' => null, + 'emptystring_param_subtest' => '', + ); + /** @var Tracker_SubmissionDao $submissionDao0 */ + $submissionDao1 = $submissionModel->createSubmission($producerDao, $uuid1, '', $params1); + $submissionDao1->setProducerRevision($producerRevision); + $submissionDao1->setUserId($userDao->getKey()); + $submissionDao1->setBuildResultsUrl('http://buildresultsurl'); + $submissionDao1->setBranch('dev'); + $submissionModel->save($submissionDao1); + + // Ensure value and params are properly set on scalar. + $paramChecks = array( + 'num_param_subtest' => array('found' => false, 'type' => 'numeric', 'val' => 92), + 'text_param_subtest' => array('found' => false, 'type' => 'text', 'val' => 'dev'), + 'emptystring_param_subtest' => array('found' => false, 'type' => 'text', 'val' => ''), + 'null_param_subtest' => array('found' => false, 'type' => 'text', 'val' => ''), + ); + + $submissionDao1Params = $submissionDao1->getParams(); + /** @var Tracker_ParamModel $param */ + foreach ($submissionDao1Params as $param) { + $checks = $paramChecks[$param->getParamName()]; + $this->assertEquals($checks['type'], $param->getParamType()); + if ($checks['type'] === 'numeric') { + $this->assertEquals($checks['val'], $param->getNumericValue()); + } else { + $this->assertEquals($checks['val'], $param->getTextValue()); + } + $paramChecks[$param->getParamName()]['found'] = true; + } + + foreach ($paramChecks as $checks) { + $this->assertTrue($checks['found']); + } + + // Delete scalars and ensure params are deleted. + $submissionModel->delete($submissionDao0); + $submissionModel->delete($submissionDao1); + + /** @var Tracker_ParamModel $submissionParam */ + foreach ($submissionDao0Params as $submissionParam) { + $submissionParamReloaded = $paramModel->load($submissionParam->getParamId()); + $this->assertFalse($submissionParamReloaded, 'Submission param 0 should have been deleted'); + } + /** @var Tracker_ParamModel $submissionParam */ + foreach ($submissionDao1Params as $submissionParam) { + $submissionParamReloaded = $paramModel->load($submissionParam->getParamId()); + $this->assertFalse($submissionParamReloaded, 'Submission param 2 should have been deleted'); + } + } +} diff --git a/modules/tracker/tests/models/base/TrendModelTest.php b/modules/tracker/tests/models/base/TrendModelTest.php deleted file mode 100644 index f71a2f6c2..000000000 --- a/modules/tracker/tests/models/base/TrendModelTest.php +++ /dev/null @@ -1,43 +0,0 @@ -setupDatabase(array('default')); // core dataset - $this->setupDatabase(array('aggregateMetric'), 'tracker'); // module dataset - $this->enabledModules = array('tracker'); - parent::setUp(); - } - - /** testGetDistinctBranchesForMetricName */ - public function testGetDistinctBranchesForMetricName() - { - /** @var Tracker_TrendModel $trendModel */ - $trendModel = MidasLoader::loadModel('Trend', 'tracker'); - /** @var array $branches */ - $branches = $trendModel->getDistinctBranchesForMetricName(100, 'Greedy error'); - $this->assertEquals(count($branches), 2); - $this->assertTrue(in_array('master', $branches)); - $this->assertTrue(in_array('test', $branches)); - } -} diff --git a/modules/tracker/views/producer/aggregatemetric.phtml b/modules/tracker/views/producer/aggregatemetric.phtml index fe62a2f21..7873ff99c 100644 --- a/modules/tracker/views/producer/aggregatemetric.phtml +++ b/modules/tracker/views/producer/aggregatemetric.phtml @@ -30,7 +30,7 @@ echo '