From 5094226753f7fadeaa70afbd5f3b41449e86933a Mon Sep 17 00:00:00 2001 From: santipalenque Date: Mon, 3 Nov 2014 17:24:52 -0300 Subject: [PATCH] [spalenque] - #6968 *WIP --- marketplace/_config.php | 3 +- .../active_records/CompanyServiceDraft.php | 205 ++++++++++++++++++ .../OpenStackImplementationDraft.php | 87 ++++++++ .../active_records/RegionalSupportDraft.php | 120 ++++++++++ .../RegionalSupportedCompanyServiceDraft.php | 50 +++++ .../ApplianceDraft.php | 9 + .../DistributionDraft.php | 9 + .../clouds/CloudServiceDraft.php | 101 +++++++++ .../clouds/PrivateCloudServiceDraft.php | 8 + .../clouds/PublicCloudServiceDraft.php | 8 + .../factories/ApplianceFactory.php | 2 +- .../factories/ConsultantFactory.php | 2 +- .../factories/DistributionDraftFactory.php | 55 +++++ .../factories/DistributionFactory.php | 3 +- .../factories/PrivateCloudFactory.php | 2 +- .../factories/PublicCloudFactory.php | 2 +- .../factories/TrainingFactory.php | 2 +- .../SapphireApplianceRepository.php | 7 +- .../SapphireCompanyServiceRepository.php | 12 + .../SapphireConsultantRepository.php | 8 +- .../SapphireDistributionRepository.php | 7 +- .../SapphirePrivateCloudRepository.php | 7 +- .../SapphirePublicCloudRepository.php | 8 +- .../restfull_api/AbstractRestfulJsonApi.php | 8 + .../marketplace/CompanyServiceCrudApi.php | 104 ++++++++- .../marketplace/DistributionCrudApi.php | 60 ++++- .../base_entities/CompanyServiceManager.php | 31 ++- .../base_entities/ICompanyServiceFactory.php | 2 +- .../code/ui/admin/MarketPlaceAdminPage.php | 14 +- marketplace/code/ui/admin/js/distribution.js | 76 ++++++- ...rketPlaceAdminPage_CompanyServiceHeader.ss | 3 +- .../MarketPlaceAdminPage_distribution.ss | 1 + 32 files changed, 974 insertions(+), 42 deletions(-) create mode 100644 marketplace/code/infrastructure/active_records/CompanyServiceDraft.php create mode 100644 marketplace/code/infrastructure/active_records/OpenStackImplementationDraft.php create mode 100644 marketplace/code/infrastructure/active_records/RegionalSupportDraft.php create mode 100644 marketplace/code/infrastructure/active_records/RegionalSupportedCompanyServiceDraft.php create mode 100644 marketplace/code/infrastructure/active_records/appliance_distributions/ApplianceDraft.php create mode 100644 marketplace/code/infrastructure/active_records/appliance_distributions/DistributionDraft.php create mode 100644 marketplace/code/infrastructure/active_records/clouds/CloudServiceDraft.php create mode 100644 marketplace/code/infrastructure/active_records/clouds/PrivateCloudServiceDraft.php create mode 100644 marketplace/code/infrastructure/active_records/clouds/PublicCloudServiceDraft.php create mode 100644 marketplace/code/infrastructure/factories/DistributionDraftFactory.php diff --git a/marketplace/_config.php b/marketplace/_config.php index 0fef7b3..130db30 100644 --- a/marketplace/_config.php +++ b/marketplace/_config.php @@ -18,6 +18,7 @@ Object::add_extension('Group', 'SecurityGroupDecorator'); Object::add_extension('Company', 'MarketPlaceCompany'); Object::add_extension('Member', 'MarketPlaceAdminMember'); Object::add_extension('Project', 'TrainingCourseRelatedProject'); + //Admin UI Object::add_extension('MarketPlaceType', 'MarketPlaceTypeAdminUI'); Object::add_extension('TrainingService', 'TrainingServiceAdminUI'); @@ -35,4 +36,4 @@ Object::add_extension('OpenStackComponent', 'OpenStackComponentAdminUI'); Object::add_extension('OpenStackApiVersion', 'OpenStackApiVersionAdminUI'); Object::add_extension('OpenStackRelease', 'OpenStackReleaseAdminUI'); Object::add_extension('OpenStackReleaseSupportedApiVersion', 'OpenStackReleaseSupportedApiVersionAdminUI'); -Object::add_extension('MarketPlaceAllowedInstance', 'MarketPlaceAllowedInstanceAdminUI'); \ No newline at end of file +Object::add_extension('MarketPlaceAllowedInstance', 'MarketPlaceAllowedInstanceAdminUI'); diff --git a/marketplace/code/infrastructure/active_records/CompanyServiceDraft.php b/marketplace/code/infrastructure/active_records/CompanyServiceDraft.php new file mode 100644 index 0000000..c8d9101 --- /dev/null +++ b/marketplace/code/infrastructure/active_records/CompanyServiceDraft.php @@ -0,0 +1,205 @@ + 'ENGINE=InnoDB'); + + static $db = array( + 'Name' => 'Varchar(255)', + 'Slug' => 'Varchar(255)', + 'Overview' => 'HTMLText', + 'Call2ActionUri' => 'Text', + 'Active' => 'Boolean', + ); + + static $has_one = array( + 'LiveService' => 'CompanyService', + 'Company' => 'Company', + 'MarketPlaceType' => 'MarketPlaceType', + 'EditedBy' => 'Member', + ); + + static $indexes = array( + 'Company_Name_Class' => array('type'=>'unique', 'value'=>'Name,CompanyID,ClassName') + ); + + static $has_many = array( + 'Resources' => 'CompanyServiceResource', + 'Videos' => 'MarketPlaceVideo', + ); + + protected function onBeforeWrite() { + //generate slug... + $this->Slug = strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $this->getName()))); + $current_user = Member::currentUser(); + if($current_user){ + $this->EditedByID = $current_user->ID; + } + parent::onBeforeWrite(); + } + + /** + * @return IMarketPlaceType + */ + protected function getDefaultMarketPlaceType(){ + return null; + } + + public function setCompany(ICompany $company) + { + AssociationFactory::getInstance()->getMany2OneAssociation($this,'Company')->setTarget($company); + } + + public function getCompany() + { + return AssociationFactory::getInstance()->getMany2OneAssociation($this,'Company')->getTarget(); + } + + public function setMarketplace(IMarketPlaceType $marketplace) + { + AssociationFactory::getInstance()->getMany2OneAssociation($this,'MarketPlaceType')->setTarget($marketplace); + } + + public function getMarketplace(){ + return AssociationFactory::getInstance()->getMany2OneAssociation($this,'MarketPlaceType')->getTarget(); + } + + public function setLiveServiceId($company_service_id) + { + $this->setField('LiveServiceID',$company_service_id); + } + + /** + * @return int + */ + public function getIdentifier() + { + return (int)$this->getField('ID'); + } + + public function getName() + { + return $this->getField('Name'); + } + + public function setName($name) + { + $this->setField('Name',trim($name)); + } + + public function getOverview() + { + return $this->getField('Overview'); + } + + public function setOverview($overview) + { + $this->setField('Overview',trim($overview)); + } + + public function getCall2ActionUri() + { + return $this->getField('Call2ActionUri'); + } + + public function setCall2ActionUri($call_2_action_uri) + { + $this->setField('Call2ActionUri', trim($call_2_action_uri)); + } + + /** + * @return bool + */ + public function isActive() + { + return (bool)$this->getField('Active'); + } + + /** + * @return void + */ + public function activate() + { + $this->setField('Active',true); + } + + /** + * @return void + */ + public function deactivate() + { + $this->setField('Active',false); + } + + public function addResource(ICompanyServiceResource $resource){ + + $new_order = 0; + $resources = $this->getResources(); + if(count($resources)>0){ + $last_one = end($resources); + $new_order = $last_one->getOrder()+1; + } + $resource->setOrder($new_order); + AssociationFactory::getInstance()->getOne2ManyAssociation($this,'Resources')->add($resource); + } + + public function getResources(){ + $query = new QueryObject($this); + $query->addOrder(QueryOrder::asc('Order')); + return AssociationFactory::getInstance()->getOne2ManyAssociation($this,'Resources',$query)->toArray(); + } + + /** + * @param array $new_sort + */ + public function sortResources(array $new_sort) + { + foreach($this->getResources() as $resource){ + $new_order = array_search($resource->getIdentifier(),$new_sort); + if(!$new_order) continue; + $resource->setOrder($new_order); + } + } + + /** + * @param IMarketPlaceVideo $video + * @return void + */ + public function addVideo(IMarketPlaceVideo $video) + { + AssociationFactory::getInstance()->getOne2ManyAssociation($this,'Videos')->add($video); + } + + /** + * @return IMarketPlaceVideo[] + */ + public function getVideos() + { + return AssociationFactory::getInstance()->getOne2ManyAssociation($this,'Videos')->toArray(); + } + + public function clearVideos() + { + + AssociationFactory::getInstance()->getOne2ManyAssociation($this,'Videos')->removeAll(); + } + + public function clearResources() + { + AssociationFactory::getInstance()->getOne2ManyAssociation($this,'Resources')->removeAll(); + } + + /** + * @return string + */ + public function getSlug() + { + return $this->getField('Slug'); + } +} \ No newline at end of file diff --git a/marketplace/code/infrastructure/active_records/OpenStackImplementationDraft.php b/marketplace/code/infrastructure/active_records/OpenStackImplementationDraft.php new file mode 100644 index 0000000..f6833e0 --- /dev/null +++ b/marketplace/code/infrastructure/active_records/OpenStackImplementationDraft.php @@ -0,0 +1,87 @@ + 'HyperVisorType', + 'Guests' => 'GuestOSType', + ); + + static $has_many = array( + 'RegionalSupports' => 'RegionalSupport', + 'Capabilities' => 'OpenStackImplementationApiCoverage' + ); + + /** + * @return IHyperVisorType[] + */ + public function getHyperVisors() + { + return AssociationFactory::getInstance()->getMany2ManyAssociation($this,'HyperVisors')->toArray(); + } + + /** + * @param IHyperVisorType $hypervisor + * @return void + */ + public function addHyperVisor(IHyperVisorType $hypervisor) + { + AssociationFactory::getInstance()->getMany2ManyAssociation($this,'HyperVisors')->add($hypervisor); + } + + /** + * @return IGuestOSType[] + */ + public function getGuests() + { + return AssociationFactory::getInstance()->getMany2ManyAssociation($this,'Guests')->toArray(); + } + + /** + * @param IGuestOSType $guest + * @return void + */ + public function addGuest(IGuestOSType $guest) + { + AssociationFactory::getInstance()->getMany2ManyAssociation($this,'Guests')->add($guest); + } + + + /** + * @return array|IOpenStackImplementationApiCoverage[] + */ + public function getCapabilities() + { + return AssociationFactory::getInstance()->getOne2ManyAssociation($this,'Capabilities')->toArray(); + } + + /** + * @param IOpenStackImplementationApiCoverage $capability + * @return void + */ + public function addCapability(IOpenStackImplementationApiCoverage $capability) + { + AssociationFactory::getInstance()->getOne2ManyAssociation($this,'Capabilities')->add($capability); + } + + public function clearCapabilities() + { + AssociationFactory::getInstance()->getOne2ManyAssociation($this,'Capabilities')->removeAll(); + } + + public function clearHypervisors() + { + AssociationFactory::getInstance()->getMany2ManyAssociation($this,'HyperVisors')->removeAll(); + } + + public function clearGuests() + { + AssociationFactory::getInstance()->getMany2ManyAssociation($this,'Guests')->removeAll(); + } + +} \ No newline at end of file diff --git a/marketplace/code/infrastructure/active_records/RegionalSupportDraft.php b/marketplace/code/infrastructure/active_records/RegionalSupportDraft.php new file mode 100644 index 0000000..70ceea9 --- /dev/null +++ b/marketplace/code/infrastructure/active_records/RegionalSupportDraft.php @@ -0,0 +1,120 @@ + 'ENGINE=InnoDB'); + + static $db = array( + 'Order' => 'Int', + ); + + static $has_one = array( + 'Region' => 'Region', + 'Service' => 'RegionalSupportedCompanyServiceDraft' + ); + + static $indexes = array( + 'Region_Service' => array('type'=>'unique', 'value'=>'RegionID,ServiceID') + ); + + static $many_many = array( + 'SupportChannelTypes' => 'SupportChannelType' + ); + + static $many_many_extraFields = array( + 'SupportChannelTypes' => array( + 'Data' => "Varchar", + ), + ); + + /** + * @return int + */ + public function getIdentifier() + { + return (int)$this->getField('ID'); + } + + /** + * @return int + */ + public function getOrder() + { + return (int)$this->getField('Order'); + } + + /** + * @param int $order + * @return void + */ + public function setOrder($order) + { + $this->setField('Order',$order); + } + + /** + * @return IRegion + */ + public function getRegion() + { + return AssociationFactory::getInstance()->getMany2OneAssociation($this,'Region')->getTarget(); + } + + /** + * @param IRegion $region + * @return void + */ + public function setRegion(IRegion $region) + { + AssociationFactory::getInstance()->getMany2OneAssociation($this,'Region')->setTarget($region); + } + + public function getSupportChannelTypes() + { + $query = new QueryObject($this); + $query->addOrder(QueryOrder::asc('SupportChannelTypeID')); + return AssociationFactory::getInstance()->getMany2ManyAssociation($this,'SupportChannelTypes', $query)->toArray(); + } + + /** + * @param ISupportChannelType $channel_type + * @param string $data + * @return void + */ + public function addSupportChannelType(ISupportChannelType $channel_type, $data) + { + $query = new QueryObject($this); + $query->addOrder(QueryOrder::asc('SupportChannelTypeID')); + AssociationFactory::getInstance()->getMany2ManyAssociation($this,'SupportChannelTypes')->add($channel_type, array('Data'=>$data)); + } + + public function clearChannelTypes(){ + $query = new QueryObject($this); + $query->addOrder(QueryOrder::asc('SupportChannelTypeID')); + AssociationFactory::getInstance()->getMany2ManyAssociation($this,'SupportChannelTypes')->removeAll(); + } + + /** + * @return IRegionalSupportedCompanyService + */ + public function getCompanyService() + { + $query = new QueryObject($this); + $query->addOrder(QueryOrder::asc('Order')); + return AssociationFactory::getInstance()->getMany2OneAssociation($this,'Service','RegionalSupports',$query)->getTarget(); + } + + /** + * @param IRegionalSupportedCompanyService $company_service + * @return void + */ + public function setCompanyService(IRegionalSupportedCompanyService $company_service) + { + $query = new QueryObject($this); + $query->addOrder(QueryOrder::asc('Order')); + AssociationFactory::getInstance()->getMany2OneAssociation($this,'Service','RegionalSupports',$query)->setTarget($company_service); + } +} \ No newline at end of file diff --git a/marketplace/code/infrastructure/active_records/RegionalSupportedCompanyServiceDraft.php b/marketplace/code/infrastructure/active_records/RegionalSupportedCompanyServiceDraft.php new file mode 100644 index 0000000..197db61 --- /dev/null +++ b/marketplace/code/infrastructure/active_records/RegionalSupportedCompanyServiceDraft.php @@ -0,0 +1,50 @@ + 'RegionalSupportDraft', + ); + + /** + * @param bool $only_new_ones + * @return IRegionalSupport[] + */ + public function getRegionalSupports($only_new_ones = false) + { + $query = new QueryObject($this); + $query->addOrder(QueryOrder::asc('Order')); + return AssociationFactory::getInstance()->getOne2ManyAssociation($this,'RegionalSupports',$query)->toArray(); + } + + /** + * @param IRegionalSupport $regional_support + * @return void + */ + public function addRegionalSupport(IRegionalSupport $regional_support) + { + $new_order = 0; + $regional_supports = $this->getRegionalSupports(); + if(count($regional_supports)>0){ + $last_one = end($regional_supports); + $new_order = $last_one->getOrder()+1; + } + $regional_support->setOrder($new_order); + AssociationFactory::getInstance()->getOne2ManyAssociation($this,'RegionalSupports')->add($regional_support); + } + + + public function clearRegionalSupports() + { + $regional_supports = AssociationFactory::getInstance()->getOne2ManyAssociation($this,'RegionalSupports'); + foreach($regional_supports as $regional_support){ + $regional_support->clearChannelTypes(); + } + $regional_supports->removeAll(); + } +} \ No newline at end of file diff --git a/marketplace/code/infrastructure/active_records/appliance_distributions/ApplianceDraft.php b/marketplace/code/infrastructure/active_records/appliance_distributions/ApplianceDraft.php new file mode 100644 index 0000000..1a36af7 --- /dev/null +++ b/marketplace/code/infrastructure/active_records/appliance_distributions/ApplianceDraft.php @@ -0,0 +1,9 @@ + 'ENGINE=InnoDB'); + + static $has_many = array( + 'DataCenters' => 'DataCenterLocation', + //@override + 'Capabilities' => 'CloudServiceOffered', + 'DataCenterRegions' => 'DataCenterRegion', + ); + + /** + * @return IDataCenterLocation[] + */ + public function getDataCentersLocations() + { + return AssociationFactory::getInstance()->getOne2ManyAssociation($this,'DataCenters')->toArray(); + } + + /** + * @param IDataCenterLocation $data_center_location + * @throws EntityValidationException + */ + public function addDataCenterLocation(IDataCenterLocation $data_center_location) + { + $data_centers = AssociationFactory::getInstance()->getOne2ManyAssociation($this,'DataCenters'); + foreach($data_centers->toArray() as $location){ + if($data_center_location->getCountry() == $location->getCountry() && $data_center_location->getCity() == $location->getCity()) + throw new EntityValidationException(array( array('message'=>sprintf('DataCenter Location ( %s - %s) already exists!.',$location->getCity(),$location->getCountry())))); + } + $data_centers->add($data_center_location); + } + + /** + * @return void + */ + public function clearDataCentersLocations() + { + $locations = AssociationFactory::getInstance()->getOne2ManyAssociation($this,'DataCenters'); + foreach($locations as $location){ + $location->clearAvailabilityZones(); + } + $locations->removeAll(); + } + + /** + * @override + */ + public function clearCapabilities() + { + $services = AssociationFactory::getInstance()->getOne2ManyAssociation($this,'Capabilities'); + foreach($services as $service){ + $service->clearPricingSchemas(); + } + $services->removeAll(); + } + + /** + * @return IDataCenterRegion[] + */ + public function getDataCenterRegions() + { + return AssociationFactory::getInstance()->getOne2ManyAssociation($this,'DataCenterRegions')->toArray(); + } + + /** + * @param IDataCenterRegion $region + * @return void + */ + public function addDataCenterRegion(IDataCenterRegion $region) + { + AssociationFactory::getInstance()->getOne2ManyAssociation($this,'DataCenterRegions')->add($region); + } + + /** + * @return void + */ + public function clearDataCenterRegions() + { + AssociationFactory::getInstance()->getOne2ManyAssociation($this,'DataCenterRegions')->removeAll(); + } + + /** + * @param string $region_slug + * @return IDataCenterRegion + */ + public function getDataCenterRegion($region_slug) + { + $regions = $this->getDataCenterRegions(); + foreach($regions as $region){ + $current_slug = strtolower(preg_replace('/[^A-Za-z0-9-]+/', '-', $region->getName())); + if($region_slug===$current_slug) return $region; + } + return false; + } +} \ No newline at end of file diff --git a/marketplace/code/infrastructure/active_records/clouds/PrivateCloudServiceDraft.php b/marketplace/code/infrastructure/active_records/clouds/PrivateCloudServiceDraft.php new file mode 100644 index 0000000..e91dc40 --- /dev/null +++ b/marketplace/code/infrastructure/active_records/clouds/PrivateCloudServiceDraft.php @@ -0,0 +1,8 @@ +setName($name); diff --git a/marketplace/code/infrastructure/factories/ConsultantFactory.php b/marketplace/code/infrastructure/factories/ConsultantFactory.php index 2189e89..37a0420 100644 --- a/marketplace/code/infrastructure/factories/ConsultantFactory.php +++ b/marketplace/code/infrastructure/factories/ConsultantFactory.php @@ -27,7 +27,7 @@ final class ConsultantFactory * @param null|string $call_2_action_url * @return ICompanyService */ - public function buildCompanyService($name, $overview, ICompany $company, $active, IMarketPlaceType $marketplace_type, $call_2_action_url = null) + public function buildCompanyService($name, $overview, ICompany $company, $active, IMarketPlaceType $marketplace_type, $call_2_action_url = null, $live_service = null) { $consultant = new Consultant; $consultant->setName($name); diff --git a/marketplace/code/infrastructure/factories/DistributionDraftFactory.php b/marketplace/code/infrastructure/factories/DistributionDraftFactory.php new file mode 100644 index 0000000..8b3b969 --- /dev/null +++ b/marketplace/code/infrastructure/factories/DistributionDraftFactory.php @@ -0,0 +1,55 @@ +setName($name); + $distribution->setOverview($overview); + $distribution->setCompany($company); + if($active) + $distribution->activate(); + else + $distribution->deactivate(); + $distribution->setMarketplace($marketplace_type); + $distribution->setCall2ActionUri($call_2_action_url); + $distribution->setLiveServiceId($live_id); + return $distribution; + } + + /** + * @param $id + * @return ICompanyService + */ + public function buildCompanyServiceById($id) + { + $distribution = new DistributionDraft; + $distribution->ID = $id; + return $distribution; + } + + /** + * @param IRegion $region + * @param IRegionalSupportedCompanyService $service + * @return IRegionalSupport + */ + public function buildRegionalSupport(IRegion $region, IRegionalSupportedCompanyService $service){ + $regional_support = new RegionalSupportDraft; + $regional_support->setRegion($region); + $regional_support->setCompanyService($service); + return $regional_support; + } +} \ No newline at end of file diff --git a/marketplace/code/infrastructure/factories/DistributionFactory.php b/marketplace/code/infrastructure/factories/DistributionFactory.php index 186b34d..c86d7c0 100644 --- a/marketplace/code/infrastructure/factories/DistributionFactory.php +++ b/marketplace/code/infrastructure/factories/DistributionFactory.php @@ -25,7 +25,7 @@ final class DistributionFactory extends OpenStackImplementationFactory { * @param null|string $call_2_action_url * @return ICompanyService */ - public function buildCompanyService($name, $overview, ICompany $company, $active, IMarketPlaceType $marketplace_type, $call_2_action_url = null) + public function buildCompanyService($name, $overview, ICompany $company, $active, IMarketPlaceType $marketplace_type, $call_2_action_url = null, $live_id = null) { $distribution = new Distribution; $distribution->setName($name); @@ -50,4 +50,5 @@ final class DistributionFactory extends OpenStackImplementationFactory { $distribution->ID = $id; return $distribution; } + } \ No newline at end of file diff --git a/marketplace/code/infrastructure/factories/PrivateCloudFactory.php b/marketplace/code/infrastructure/factories/PrivateCloudFactory.php index 9cd9516..a4ac16a 100644 --- a/marketplace/code/infrastructure/factories/PrivateCloudFactory.php +++ b/marketplace/code/infrastructure/factories/PrivateCloudFactory.php @@ -24,7 +24,7 @@ final class PrivateCloudFactory extends CloudFactory { * @param null|string $call_2_action_url * @return ICompanyService */ - public function buildCompanyService($name, $overview, ICompany $company, $active, IMarketPlaceType $marketplace_type, $call_2_action_url = null) + public function buildCompanyService($name, $overview, ICompany $company, $active, IMarketPlaceType $marketplace_type, $call_2_action_url = null, $live_service = null) { $private_cloud = new PrivateCloudService; $private_cloud->setName($name); diff --git a/marketplace/code/infrastructure/factories/PublicCloudFactory.php b/marketplace/code/infrastructure/factories/PublicCloudFactory.php index c1db350..1c74597 100644 --- a/marketplace/code/infrastructure/factories/PublicCloudFactory.php +++ b/marketplace/code/infrastructure/factories/PublicCloudFactory.php @@ -26,7 +26,7 @@ final class PublicCloudFactory * @param null|string $call_2_action_url * @return ICompanyService */ - public function buildCompanyService($name, $overview, ICompany $company, $active, IMarketPlaceType $marketplace_type, $call_2_action_url = null) + public function buildCompanyService($name, $overview, ICompany $company, $active, IMarketPlaceType $marketplace_type, $call_2_action_url = null, $live_service = null) { $public_cloud = new PublicCloudService; $public_cloud->setName($name); diff --git a/marketplace/code/infrastructure/factories/TrainingFactory.php b/marketplace/code/infrastructure/factories/TrainingFactory.php index c4da398..613d1db 100644 --- a/marketplace/code/infrastructure/factories/TrainingFactory.php +++ b/marketplace/code/infrastructure/factories/TrainingFactory.php @@ -25,7 +25,7 @@ final class TrainingFactory implements ITrainingFactory { * @param null|string $call_2_action_url * @return ICompanyService */ - public function buildCompanyService($name, $overview, ICompany $company, $active, IMarketPlaceType $marketplace_type, $call_2_action_url = null) + public function buildCompanyService($name, $overview, ICompany $company, $active, IMarketPlaceType $marketplace_type, $call_2_action_url = null, $live_service = null) { $training = new TrainingService; $training->setName($name); diff --git a/marketplace/code/infrastructure/repositories/SapphireApplianceRepository.php b/marketplace/code/infrastructure/repositories/SapphireApplianceRepository.php index 42ff21f..0172db0 100644 --- a/marketplace/code/infrastructure/repositories/SapphireApplianceRepository.php +++ b/marketplace/code/infrastructure/repositories/SapphireApplianceRepository.php @@ -16,9 +16,10 @@ */ final class SapphireApplianceRepository extends SapphireOpenStackImplementationRepository { - public function __construct(){ - parent::__construct(new Appliance()); - } + public function __construct($draft_entity=false){ + $entity = ($draft_entity) ? new ApplianceDraft() : new Appliance(); + parent::__construct($entity); + } /** * @return string diff --git a/marketplace/code/infrastructure/repositories/SapphireCompanyServiceRepository.php b/marketplace/code/infrastructure/repositories/SapphireCompanyServiceRepository.php index d6a5d9f..eb7f547 100644 --- a/marketplace/code/infrastructure/repositories/SapphireCompanyServiceRepository.php +++ b/marketplace/code/infrastructure/repositories/SapphireCompanyServiceRepository.php @@ -74,4 +74,16 @@ abstract class SapphireCompanyServiceRepository $res = is_null($ds)?array():$ds->toArray(); return $res; } + + /** + * @param int $id + * @return ICompanyService + */ + public function getByLiveServiceId($id) + { + $query = new QueryObject(); + $query->addAddCondition(QueryCriteria::equal('LiveServiceID',$id)); + return $this->getBy($query); + } + } \ No newline at end of file diff --git a/marketplace/code/infrastructure/repositories/SapphireConsultantRepository.php b/marketplace/code/infrastructure/repositories/SapphireConsultantRepository.php index e25a2e6..66594fc 100644 --- a/marketplace/code/infrastructure/repositories/SapphireConsultantRepository.php +++ b/marketplace/code/infrastructure/repositories/SapphireConsultantRepository.php @@ -16,9 +16,11 @@ */ final class SapphireConsultantRepository extends SapphireRegionalSupportedCompanyServiceRepository { - public function __construct(){ - parent::__construct(new Consultant); - } + + public function __construct($draft_entity=false){ + $entity = ($draft_entity) ? new ConsultantDraft() : new Consultant(); + parent::__construct($entity); + } public function delete(IEntity $entity){ $entity->clearClients(); diff --git a/marketplace/code/infrastructure/repositories/SapphireDistributionRepository.php b/marketplace/code/infrastructure/repositories/SapphireDistributionRepository.php index dcc2436..a55bab2 100644 --- a/marketplace/code/infrastructure/repositories/SapphireDistributionRepository.php +++ b/marketplace/code/infrastructure/repositories/SapphireDistributionRepository.php @@ -16,10 +16,11 @@ */ class SapphireDistributionRepository extends SapphireOpenStackImplementationRepository - { - public function __construct(){ - parent::__construct(new Distribution); + + public function __construct($draft_entity=false){ + $entity = ($draft_entity) ? new DistributionDraft() : new Distribution(); + parent::__construct($entity); } /** diff --git a/marketplace/code/infrastructure/repositories/SapphirePrivateCloudRepository.php b/marketplace/code/infrastructure/repositories/SapphirePrivateCloudRepository.php index ad1ed4a..ad28e9b 100644 --- a/marketplace/code/infrastructure/repositories/SapphirePrivateCloudRepository.php +++ b/marketplace/code/infrastructure/repositories/SapphirePrivateCloudRepository.php @@ -17,9 +17,10 @@ final class SapphirePrivateCloudRepository extends SapphireOpenStackImplementationRepository { - public function __construct(){ - parent::__construct(new PrivateCloudService); - } + public function __construct($draft_entity=false){ + $entity = ($draft_entity) ? new PrivateCloudServiceDraft() : new PublicCloudService(); + parent::__construct($entity); + } public function delete(IEntity $entity){ diff --git a/marketplace/code/infrastructure/repositories/SapphirePublicCloudRepository.php b/marketplace/code/infrastructure/repositories/SapphirePublicCloudRepository.php index 9e7789d..6a4bc0d 100644 --- a/marketplace/code/infrastructure/repositories/SapphirePublicCloudRepository.php +++ b/marketplace/code/infrastructure/repositories/SapphirePublicCloudRepository.php @@ -16,9 +16,11 @@ */ class SapphirePublicCloudRepository extends SapphireOpenStackImplementationRepository { - public function __construct(){ - parent::__construct(new PublicCloudService); - } + + public function __construct($draft_entity=false){ + $entity = ($draft_entity) ? new PublicCloudServiceDraft() : new PublicCloudService(); + parent::__construct($entity); + } public function delete(IEntity $entity){ $entity->clearDataCenterRegions(); diff --git a/marketplace/code/interfaces/restfull_api/AbstractRestfulJsonApi.php b/marketplace/code/interfaces/restfull_api/AbstractRestfulJsonApi.php index 896634e..b948f0e 100644 --- a/marketplace/code/interfaces/restfull_api/AbstractRestfulJsonApi.php +++ b/marketplace/code/interfaces/restfull_api/AbstractRestfulJsonApi.php @@ -197,6 +197,14 @@ abstract class AbstractRestfulJsonApi extends Controller { return $response; } + protected function published(){ + $response = new SS_HTTPResponse(); + $response->setStatusCode(204); + $response->addHeader('Content-Type', 'application/json'); + $response->setBody(''); + return $response; + } + public function serverError(){ $response = new SS_HTTPResponse(); $response->setStatusCode(500); diff --git a/marketplace/code/interfaces/restfull_api/marketplace/CompanyServiceCrudApi.php b/marketplace/code/interfaces/restfull_api/marketplace/CompanyServiceCrudApi.php index 9093efd..20e5404 100644 --- a/marketplace/code/interfaces/restfull_api/marketplace/CompanyServiceCrudApi.php +++ b/marketplace/code/interfaces/restfull_api/marketplace/CompanyServiceCrudApi.php @@ -31,18 +31,30 @@ abstract class CompanyServiceCrudApi */ protected $manager; + /** + * @var CompanyServiceManager + */ + protected $draft_manager; + /** * @var ICompanyServiceFactory */ protected $factory; + /** + * @var ICompanyServiceFactory + */ + protected $draft_factory; + /** * @param CompanyServiceManager $manager * @param ICompanyServiceFactory $factory */ - public function __construct(CompanyServiceManager $manager, ICompanyServiceFactory $factory) { + public function __construct(CompanyServiceManager $manager, CompanyServiceManager $draft_manager, ICompanyServiceFactory $factory, ICompanyServiceFactory $draft_factory) { $this->manager = $manager; + $this->draft_manager = $draft_manager; $this->factory = $factory; + $this->draft_factory = $draft_factory; parent::__construct(); } @@ -111,4 +123,94 @@ abstract class CompanyServiceCrudApi return $this->serverError(); } } + + /** + * @return SS_HTTPResponse + */ + public function addCompanyServiceDraft(){ + try { + $data = $this->getJsonRequest(); + if (!$data) return $this->serverError(); + return $this->created($this->draft_manager->addCompanyService($data)->getIdentifier()); + } + catch (EntityAlreadyExistsException $ex1) { + SS_Log::log($ex1,SS_Log::ERR); + return $this->addingDuplicate($ex1->getMessage()); + } + catch (PolicyException $ex2) { + SS_Log::log($ex2,SS_Log::ERR); + return $this->validationError($ex2->getMessage()); + } + catch (EntityValidationException $ex3) { + SS_Log::log($ex3,SS_Log::ERR); + return $this->validationError($ex3->getMessages()); + } + } + + /** + * @return SS_HTTPResponse + */ + public function updateCompanyServiceDraft(){ + try { + $data = $this->getJsonRequest(); + if (!$data) return $this->serverError(); + $this->draft_manager->updateCompanyService($data); + return $this->updated(); + } + catch (EntityAlreadyExistsException $ex1) { + SS_Log::log($ex1,SS_Log::ERR); + return $this->addingDuplicate($ex1->getMessage()); + } + catch (PolicyException $ex2) { + SS_Log::log($ex2,SS_Log::ERR); + return $this->validationError($ex2->getMessage()); + } + catch (EntityValidationException $ex3) { + SS_Log::log($ex3,SS_Log::ERR); + return $this->validationError($ex3->getMessages()); + } + } + + /** + * @return SS_HTTPResponse + */ + public function deleteCompanyServiceDraft(){ + try { + $company_service_id = intval($this->request->param('COMPANY_SERVICE_ID')); + $this->draft_manager->unRegister($this->draft_factory->buildCompanyServiceById($company_service_id)); + return $this->deleted(); + } + catch (NotFoundEntityException $ex1) { + SS_Log::log($ex1,SS_Log::ERR); + return $this->notFound($ex1->getMessage()); + } + catch (Exception $ex) { + SS_Log::log($ex,SS_Log::ERR); + return $this->serverError(); + } + } + + /** + * @return SS_HTTPResponse + */ + public function publishCompanyService(){ + try { + $data = $this->getJsonRequest(); + if (!$data) return $this->serverError(); + $this->manager->publishCompanyService($data); + return $this->published(); + } + catch (EntityAlreadyExistsException $ex1) { + SS_Log::log($ex1,SS_Log::ERR); + return $this->addingDuplicate($ex1->getMessage()); + } + catch (PolicyException $ex2) { + SS_Log::log($ex2,SS_Log::ERR); + return $this->validationError($ex2->getMessage()); + } + catch (EntityValidationException $ex3) { + SS_Log::log($ex3,SS_Log::ERR); + return $this->validationError($ex3->getMessages()); + } + } } \ No newline at end of file diff --git a/marketplace/code/interfaces/restfull_api/marketplace/DistributionCrudApi.php b/marketplace/code/interfaces/restfull_api/marketplace/DistributionCrudApi.php index 52ff19b..a48a0ec 100644 --- a/marketplace/code/interfaces/restfull_api/marketplace/DistributionCrudApi.php +++ b/marketplace/code/interfaces/restfull_api/marketplace/DistributionCrudApi.php @@ -18,12 +18,14 @@ final class DistributionCrudApi extends CompanyServiceCrudApi { private $marketplace_type_repository; private $distribution_repository; + private $distribution_draft_repository; public function __construct() { - $this->distribution_repository = new SapphireDistributionRepository; - $this->marketplace_type_repository = new SapphireMarketPlaceTypeRepository; + $this->distribution_repository = new SapphireDistributionRepository; + $this->distribution_draft_repository = new SapphireDistributionRepository(true); + $this->marketplace_type_repository = new SapphireMarketPlaceTypeRepository; $manager = new DistributionManager ( $this->distribution_repository, @@ -49,12 +51,36 @@ final class DistributionCrudApi extends CompanyServiceCrudApi { SapphireTransactionManager::getInstance() ); + $draft_manager = new DistributionManager ( + $this->distribution_draft_repository, + new SapphireMarketPlaceVideoTypeRepository, + $this->marketplace_type_repository, + new SapphireGuestOSTypeRepository, + new SapphireHyperVisorTypeRepository, + new SapphireOpenStackApiVersionRepository, + new SapphireOpenStackComponentRepository, + new SapphireOpenStackReleaseRepository, + new SapphireRegionRepository, + new SapphireSupportChannelTypeRepository, + new SapphireOpenStackReleaseSupportedApiVersionRepository, + new DistributionAddPolicy($this->distribution_draft_repository, $this->marketplace_type_repository), + new CompanyServiceCanAddResourcePolicy, + new CompanyServiceCanAddVideoPolicy, + new DistributionDraftFactory, + new MarketplaceFactory, + new ValidatorFactory, + new OpenStackApiFactory, + null, + new SessionCacheService, + SapphireTransactionManager::getInstance() + ); - parent::__construct($manager,new DistributionFactory); + + parent::__construct($manager,$draft_manager,new DistributionFactory,new DistributionDraftFactory); // filters ... $this_var = $this; $current_user = $this->current_user; - $repository = $this->distribution_repository; + $repository = $this->distribution_draft_repository; $this->addBeforeFilter('addCompanyService','check_add_company',function ($request) use($this_var, $current_user, $repository){ $data = $this_var->getJsonRequest(); @@ -87,6 +113,7 @@ final class DistributionCrudApi extends CompanyServiceCrudApi { 'DELETE $COMPANY_SERVICE_ID!' => 'deleteCompanyService', 'POST ' => 'addCompanyService', 'PUT ' => 'updateCompanyService', + 'PUBLISH ' => 'publishCompanyService', ); /** @@ -96,7 +123,8 @@ final class DistributionCrudApi extends CompanyServiceCrudApi { 'getDistribution', 'deleteCompanyService', 'addCompanyService', - 'updateCompanyService' + 'updateCompanyService', + 'publishCompanyService' ); public function getDistribution(){ @@ -107,9 +135,18 @@ final class DistributionCrudApi extends CompanyServiceCrudApi { return $this->ok(OpenStackImplementationAssembler::convertOpenStackImplementationToArray($distribution)); } + public function getDistributionDraft(){ + $company_service_id = intval($this->request->param('COMPANY_SERVICE_ID')); + $distribution = $this->distribution_draft_repository->getByLiveServiceId($company_service_id); + if(!$distribution) + return $this->notFound(); + return $this->ok(OpenStackImplementationAssembler::convertOpenStackImplementationToArray($distribution)); + } + public function addCompanyService(){ try { return parent::addCompanyService(); + //return parent::addCompanyServiceDraft(); } catch (Exception $ex) { SS_Log::log($ex,SS_Log::ERR); @@ -119,11 +156,22 @@ final class DistributionCrudApi extends CompanyServiceCrudApi { public function updateCompanyService(){ try { - return parent::updateCompanyService(); + return parent::updateCompanyServiceDraft(); } catch (Exception $ex) { SS_Log::log($ex,SS_Log::ERR); return $this->serverError(); } } + + public function publishCompanyService(){ + try { + return parent::publishCompanyService(); + } + catch (Exception $ex) { + SS_Log::log($ex,SS_Log::ERR); + return $this->serverError(); + } + } + } \ No newline at end of file diff --git a/marketplace/code/model/base_entities/CompanyServiceManager.php b/marketplace/code/model/base_entities/CompanyServiceManager.php index 01bae94..47684a3 100644 --- a/marketplace/code/model/base_entities/CompanyServiceManager.php +++ b/marketplace/code/model/base_entities/CompanyServiceManager.php @@ -20,6 +20,7 @@ abstract class CompanyServiceManager { * @var ITransactionManager */ protected $tx_manager; + /** * @var ICompanyServiceRepository */ @@ -35,7 +36,6 @@ abstract class CompanyServiceManager { */ protected $add_resource_policy; - /** * @var ICompanyServiceCanAddVideoPolicy */ @@ -139,19 +139,20 @@ abstract class CompanyServiceManager { */ public function register(ICompanyService &$company_service){ + $repository = $this->repository; + if(!is_null($this->add_policy)) $this->add_policy->canAdd($company_service->getCompany()); $query = new QueryObject($company_service); $query->addAddCondition(QueryCriteria::equal('Name',$company_service->getName())); $query->addAddCondition(QueryCriteria::equal('Company.ID',$company_service->getCompany()->getIdentifier())); - $res = $this->repository->getBy($query); + $res = $repository->getBy($query); if($res) throw new EntityAlreadyExistsException('CompanyService',sprintf('name %s',$company_service->getName())); - return $this->repository->add($company_service); + return $repository->add($company_service); } - /** * @return IMarketPlaceType * @throws NotFoundEntityException @@ -184,15 +185,18 @@ abstract class CompanyServiceManager { $getMarketPlaceType = new ReflectionMethod(get_class($this_var) ,'getMarketPlaceType'); $getMarketPlaceType->setAccessible(true); $company = $marketplace_factory->buildCompanyById(intval($data['company_id'])); + $live_service_id = (isset($data['live_service_id'])) ? $data['live_service_id'] : null; + $company_service = $factory->buildCompanyService( $data['name'], $data['overview'], $company, $data['active'], $getMarketPlaceType->invoke($this_var), - $data['call_2_action_uri']); + $data['call_2_action_uri'], + $live_service_id); - $this_var->register($company_service); + $this_var->register($company_service); $updateCollections = new ReflectionMethod(get_class($this_var),'updateCollections'); $updateCollections->setAccessible(true); @@ -321,6 +325,7 @@ abstract class CompanyServiceManager { $company_service->addResource($resource); return $resource->getIdentifier(); } + /** * @param array $messages * @throws EntityValidationException @@ -374,4 +379,16 @@ abstract class CompanyServiceManager { } return $services; } -} \ No newline at end of file + + /** + * @param int $version_id + * @return IEntity|void + * @throws EntityAlreadyExistsException + * @throws NotFoundEntityException + */ + public function publishCompanyService(array $data){ + + + } + +} diff --git a/marketplace/code/model/base_entities/ICompanyServiceFactory.php b/marketplace/code/model/base_entities/ICompanyServiceFactory.php index a2d8170..5c8a279 100644 --- a/marketplace/code/model/base_entities/ICompanyServiceFactory.php +++ b/marketplace/code/model/base_entities/ICompanyServiceFactory.php @@ -24,7 +24,7 @@ interface ICompanyServiceFactory { * @param null|string $call_2_action_url * @return ICompanyService */ - public function buildCompanyService($name, $overview, ICompany $company, $active, IMarketPlaceType $marketplace_type,$call_2_action_url=null); + public function buildCompanyService($name, $overview, ICompany $company, $active, IMarketPlaceType $marketplace_type,$call_2_action_url=null,$live_id=null); /** * @param $id diff --git a/marketplace/code/ui/admin/MarketPlaceAdminPage.php b/marketplace/code/ui/admin/MarketPlaceAdminPage.php index f971e29..d1ddd4d 100644 --- a/marketplace/code/ui/admin/MarketPlaceAdminPage.php +++ b/marketplace/code/ui/admin/MarketPlaceAdminPage.php @@ -47,6 +47,10 @@ class MarketPlaceAdminPage_Controller extends Page_Controller * @var ICompanyServiceRepository */ private $distribution_repository; + /** + * @var ICompanyServiceRepository + */ + private $distribution_draft_repository; /** * @var ICompanyServiceRepository @@ -140,6 +144,7 @@ class MarketPlaceAdminPage_Controller extends Page_Controller $this->marketplace_repository = new SapphireMarketPlaceTypeRepository; $this->companies_with_marketplace_creation_rights = new CompaniesWithMarketplaceCreationRightsSapphireQueryHandler; $this->distribution_repository = new SapphireDistributionRepository; + $this->distribution_draft_repository = new SapphireDistributionRepository(true); $this->appliance_repository = new SapphireApplianceRepository; $this->components_repository = new SapphireOpenStackComponentRepository; $this->hyper_visors_repository = new SapphireHyperVisorTypeRepository; @@ -280,10 +285,15 @@ class MarketPlaceAdminPage_Controller extends Page_Controller public function getCurrentDistribution() { $distribution_id = intval($this->request->getVar('id')); + $distribution = false; if ($distribution_id > 0) { - return $this->distribution_repository->getById($distribution_id); + $distribution = $this->distribution_draft_repository->getByLiveServiceId($distribution_id); + //if no draft found we pull the live one to create the draft from it when saved + if (!$distribution) { + $distribution = $this->distribution_repository->getById($distribution_id); + } } - return false; + return $distribution; } public function getCurrentAppliance() diff --git a/marketplace/code/ui/admin/js/distribution.js b/marketplace/code/ui/admin/js/distribution.js index 6152789..eac85a8 100644 --- a/marketplace/code/ui/admin/js/distribution.js +++ b/marketplace/code/ui/admin/js/distribution.js @@ -39,7 +39,15 @@ jQuery(document).ready(function($){ else{ $('#active',form).prop('checked',false); } - $("#id",form).val(distribution.id); + + //this is a draft + if (distribution.live_service_id) { + $("#id",form).val(distribution.id); + $("#live_id",form).val(distribution.live_service_id); + } else { //its not a draft is the live version, so we remove the id and set the live_service_id + $("#live_id",form).val(distribution.id); + } + //reload widgets $("#components_form").components('load',distribution.capabilities); $("#hypervisors_form").hypervisors('load',distribution.hypervisors); @@ -68,6 +76,69 @@ jQuery(document).ready(function($){ var hypervisors = $("#hypervisors_form").hypervisors('serialize'); var videos = $("#videos-form").videos('serialize'); + if(additional_resources !== false && + regional_support !== false && + capabilities !== false && + guest_os !== false && + hypervisors !== false && + videos !== false){ + + //create distribution object and POST it + var distribution = {}; + distribution.id = parseInt($("#id",form).val()); + distribution.live_service_id = parseInt($("#live_id",form).val()); + distribution.company_id = parseInt($("#company_id",form).val()); + distribution.name = $("#name",form).val(); + distribution.overview = $("#overview",form).val(); + distribution.call_2_action_uri = $("#call_2_action_uri",form).val(); + distribution.active = $('#active',form).is(":checked"); + distribution.videos = videos; + distribution.hypervisors = hypervisors; + distribution.guest_os = guest_os; + distribution.capabilities = capabilities; + distribution.regional_support = regional_support; + distribution.additional_resources = additional_resources; + + var type = distribution.id > 0 ?'PUT':'POST'; + + $('.save-distribution').prop('disabled',true); + $.ajax({ + type: type, + url: 'api/v1/marketplace/distributions', + data: JSON.stringify(distribution), + contentType: "application/json; charset=utf-8", + dataType: "json", + success: function (data,textStatus,jqXHR) { + window.location = listing_url; + }, + error: function (jqXHR, textStatus, errorThrown) { + $('.save-distribution').prop('disabled',false); + ajaxError(jqXHR, textStatus, errorThrown); + } + }); + } + return false; + }); + + $('.publish-distribution').click(function(event){ + event.preventDefault(); + event.stopPropagation(); + var button = $(this); + if(button.prop('disabled')){ + return false; + } + var form_validator = form.marketplace_type_header('getFormValidator'); + form_validator.settings.ignore = ".add-comtrol"; + var is_valid = form.valid(); + if(!is_valid) return false; + form_validator.resetForm(); + var additional_resources = $("#additional-resources-form").additional_resources('serialize'); + var regional_support = $("#support-channels-form").support_channels('serialize'); + var capabilities = $("#components_form").components('serialize'); + var guest_os = $("#guest_os_form").guest_os('serialize'); + var hypervisors = $("#hypervisors_form").hypervisors('serialize'); + var videos = $("#videos-form").videos('serialize'); + if(additional_resources !== false && regional_support !== false && capabilities !== false && @@ -90,7 +161,7 @@ jQuery(document).ready(function($){ distribution.regional_support = regional_support; distribution.additional_resources = additional_resources; - var type = distribution.id > 0 ?'PUT':'POST'; + var type = 'PUBLISH'; $('.save-distribution').prop('disabled',true); $.ajax({ @@ -109,6 +180,7 @@ jQuery(document).ready(function($){ }); } return false; + }); } }); diff --git a/marketplace/templates/Layout/Includes/MarketPlaceAdminPage_CompanyServiceHeader.ss b/marketplace/templates/Layout/Includes/MarketPlaceAdminPage_CompanyServiceHeader.ss index 58b80bc..86703a1 100644 --- a/marketplace/templates/Layout/Includes/MarketPlaceAdminPage_CompanyServiceHeader.ss +++ b/marketplace/templates/Layout/Includes/MarketPlaceAdminPage_CompanyServiceHeader.ss @@ -36,4 +36,5 @@ - \ No newline at end of file + + diff --git a/marketplace/templates/Layout/MarketPlaceAdminPage_distribution.ss b/marketplace/templates/Layout/MarketPlaceAdminPage_distribution.ss index 0278cbf..7126c18 100644 --- a/marketplace/templates/Layout/MarketPlaceAdminPage_distribution.ss +++ b/marketplace/templates/Layout/MarketPlaceAdminPage_distribution.ss @@ -3,6 +3,7 @@

Distribution - Product Details

Save + Publish <% if CurrentDistribution %> Preview <% end_if %>