diff --git a/modules/tracker/controllers/components/ApiComponent.php b/modules/tracker/controllers/components/ApiComponent.php index da721920a..c2cf1934d 100644 --- a/modules/tracker/controllers/components/ApiComponent.php +++ b/modules/tracker/controllers/components/ApiComponent.php @@ -125,7 +125,9 @@ public function itemAssociate($args) } /** - * Create a new scalar data point (must have write access to the community). + * Create a new scalar data point (must have write access to the community), + * creating a producer along the way if the requested producer does not + * already exist. * * @param communityId The id of the community that owns the producer * @param producerDisplayName The display name of the producer @@ -305,19 +307,22 @@ private function _createOrFindByName($itemName, $community) } /** - * Create a new submission. + * Create a new submission (must have write access to the community), + * creating a producer along the way if the requested producer does not + * already exist. * + * @param communityId The community attached to the producer + * @param producerDisplayName Displayed name of the producer * @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 submitTime (Optional) The submit timestamp. Must be parseable with PHP strtotime() + * @param branch (Optional) The branch name within the source repository * @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 extraUrls (Optional) JSON list of additional links * @param reproductionCommand (Optional) If passed, the command to produce this scalar + * * @return The submission DAO that was created * @throws Exception */ diff --git a/modules/tracker/controllers/components/ApisubmissionComponent.php b/modules/tracker/controllers/components/ApisubmissionComponent.php index e515fd74a..7d63e0412 100644 --- a/modules/tracker/controllers/components/ApisubmissionComponent.php +++ b/modules/tracker/controllers/components/ApisubmissionComponent.php @@ -147,21 +147,42 @@ public function index($args) */ public function post($args) { - /** @var ApihelperComponent $apihelperComponent */ - $apihelperComponent = MidasLoader::loadComponent('Apihelper'); - $apihelperComponent->requirePolicyScopes( + /** @var ApihelperComponent $apiHelperComponent */ + $apiHelperComponent = MidasLoader::loadComponent('Apihelper'); + + /** @var CommunityModel $communityModel */ + $communityModel = MidasLoader::loadModel('Community'); + /** @var Tracker_SubmissionModel $submissionModel */ + $submissionModel = MidasLoader::loadModel('Submission', + $this->moduleName); + /** @var Tracker_ProducerModel $producerModel */ + $producerModel = MidasLoader::loadModel('Producer', $this->moduleName); + + $apiHelperComponent->requirePolicyScopes( array(MIDAS_API_PERMISSION_SCOPE_WRITE_DATA)); - $apihelperComponent->validateParams($args, array('communityId', 'producerDisplayName', 'producerRevision')); + $apiHelperComponent->validateParams($args, array('communityId', 'producerDisplayName', 'producerRevision')); $this->_checkUser($args, 'Only authenticated users can create submissions.'); + $user = $apiHelperComponent->getUser($args); + + /** @var CommunityDao $community */ + $community = $communityModel->load($args['communityId']); + if (!$community || !$communityModel->policyCheck( + $community, + $user, + MIDAS_POLICY_WRITE + ) + ) { + throw new Exception('Write permission required on community', 403); + } - /** @var Tracker_SubmissionModel $submissionModel */ - $submissionModel = MidasLoader::loadModel('Submission', - $this->moduleName); + $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', $this->moduleName); + $producer = $producerModel->createIfNeeded($community->getKey(), $producerDisplayName); if (!isset($args['uuid'])) { /** @var UuidComponent $uuidComponent */ @@ -185,12 +206,8 @@ public function post($args) $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(); + + $args['producer_id'] = $producer->getKey(); // Remove params from the submission args for later insertion in param table if (isset($args['params']) && !is_null($args['params'])) { diff --git a/modules/tracker/models/base/ProducerModelBase.php b/modules/tracker/models/base/ProducerModelBase.php index fc41e1b32..90cfa3ab5 100644 --- a/modules/tracker/models/base/ProducerModelBase.php +++ b/modules/tracker/models/base/ProducerModelBase.php @@ -42,9 +42,9 @@ public function __construct() 'parent_column' => 'community_id', 'child_column' => 'community_id', ), - 'trends' => array( + 'trendgroups' => array( 'type' => MIDAS_ONE_TO_MANY, - 'model' => 'Trend', + 'model' => 'Trendgroup', 'module' => $this->moduleName, 'parent_column' => 'producer_id', 'child_column' => 'producer_id', @@ -106,13 +106,13 @@ public function createIfNeeded($communityId, $displayName) */ public function delete($producerDao) { - /** @var Tracker_TrendModel $trendModel */ - $trendModel = MidasLoader::loadModel('Trend', $this->moduleName); - $trendDaos = $producerDao->getTrends(); + /** @var Tracker_TrendgroupModel $trendgroupModel */ + $trendgroupModel = MidasLoader::loadModel('Trendgroup', $this->moduleName); + $trendgroupDaos = $producerDao->getTrendgroups(); - /** @var Tracker_TrendDao $trendDao */ - foreach ($trendDaos as $trendDao) { - $trendModel->delete($trendDao); + /** @var Tracker_TrendgroupDao $trendgroupDao */ + foreach ($trendgroupDaos as $trendgroupDao) { + $trendgroupModel->delete($trendgroupDao); } parent::delete($producerDao); diff --git a/modules/tracker/models/base/TrendgroupModelBase.php b/modules/tracker/models/base/TrendgroupModelBase.php index c0d062f73..359fab3a4 100644 --- a/modules/tracker/models/base/TrendgroupModelBase.php +++ b/modules/tracker/models/base/TrendgroupModelBase.php @@ -71,6 +71,25 @@ public function __construct() $this->initialize(); } + /** + * Delete the trend group and all of its subordinate trends. + * + * @param Tracker_TrendgroupDao $dao + */ + public function delete($dao) + { + /** @var Tracker_TrendModel $trendModel */ + $trendModel = MidasLoader::loadModel('Trend', $this->moduleName); + $trends = $dao->getTrends(); + + /** @var Tracker_TrendDao $trend */ + foreach ($trends as $trend) { + $trendModel->delete($trend); + } + + parent::delete($dao); + } + /** * Return the trendgroup DAO that matches the given producer id and associated item if the trendgroup exists. * Otherwise, create the trend DAO. diff --git a/modules/tracker/models/dao/ProducerDao.php b/modules/tracker/models/dao/ProducerDao.php index 0122403b5..547662dc1 100644 --- a/modules/tracker/models/dao/ProducerDao.php +++ b/modules/tracker/models/dao/ProducerDao.php @@ -37,8 +37,8 @@ * @method void setDescription(string $description) * @method CommunityDao getCommunity() * @method void setCommunity(CommunityDao $communityDao) - * @method array getTrends() - * @method void setTrends(array $trendDaos) + * @method array getTrendgroups() + * @method void setTrendgroups(array $trendgroupDaos) */ class Tracker_ProducerDao extends Tracker_AppDao { diff --git a/modules/tracker/models/dao/SubmissionDao.php b/modules/tracker/models/dao/SubmissionDao.php index ddcdf6b83..9f0c61983 100644 --- a/modules/tracker/models/dao/SubmissionDao.php +++ b/modules/tracker/models/dao/SubmissionDao.php @@ -23,6 +23,8 @@ * * @method int getSubmissionId() * @method void setSubmissionId(int $submissionId) + * @method int getProducerId() + * @method void setProducerId(int $producerId) * @method int getUserId() * @method void setUserId(int $userId) * @method string getName() diff --git a/modules/tracker/tests/controllers/ApiComponentTest.php b/modules/tracker/tests/controllers/ApiComponentTest.php index c2999d010..f7b801096 100644 --- a/modules/tracker/tests/controllers/ApiComponentTest.php +++ b/modules/tracker/tests/controllers/ApiComponentTest.php @@ -702,4 +702,49 @@ public function testAggregatemetricspecNotificationEndpoints() $notifiedUsers = $notifications[0]->users; $this->assertEquals(0, count($notifiedUsers)); } + + /** + * Test that submissions to a producer that does not yet exist will create a producer. + * + * @throws Zend_Exception + */ + public function testSubmissionProducerCreation() + { + /** @var UuidComponent $uuidComponent */ + $uuidComponent = MidasLoader::loadComponent('Uuid'); + $uuid = $uuidComponent->generate(); + + /** @var Tracker_ProducerModel $producerModel */ + $producerModel = MidasLoader::loadModel('Producer', 'tracker'); + /** @var Tracker_SubmissionModel $submissionModel */ + $submissionModel = MidasLoader::loadModel('Submission', 'tracker'); + + $token = $this->_loginAsAdministrator(); + + $testName = 'Brand new producer'; + + $shouldNotBeAProducer = $producerModel->getByCommunityIdAndName(2000, $testName); + $this->assertFalse($shouldNotBeAProducer); + + $this->resetAll(); + $this->params['method'] = 'midas.tracker.submission.add'; + $this->params['token'] = $token; + $this->params['communityId'] = '2000'; + $this->params['producerDisplayName'] = $testName; + $this->params['producerRevision'] = 'deadbeef'; + $this->params['submitTime'] = 'now'; + $this->params['uuid'] = $uuid; + $res = $this->_callJsonApi(); + + /** @var Tracker_SubmissionDao $submission */ + $submission = $submissionModel->initDao('Submission', + json_decode(json_encode($res->data), true), $this->moduleName); + /** @var Tracker_ProducerDao $producer */ + $producer = $producerModel->getByCommunityIdAndName(2000, $testName); + + $this->assertEquals($submission->getProducerId(), $producer->getKey()); + + $producerModel->delete($producer); + $submissionModel->delete($submission); + } }