Esempio n. 1
0
    def validate_upgrade(self, provider, product_spec):

        if 'version' in product_spec and 'productSpecCharacteristic' in product_spec:
            # Extract product needed characteristics
            asset_t, media_type, url, asset_id = self.parse_characteristics(product_spec)
            is_digital = asset_t is not None and media_type is not None and url is not None

            if is_digital:
                asset, lock = self._get_upgrading_asset(asset_t, url, product_spec['id'])

                self._to_downgrade = asset

                self._validate_product_characteristics(asset, provider, asset_t, media_type)

                # Check product version
                if not is_valid_version(product_spec['version']):
                    raise ProductError('The field version does not have a valid format')

                if not is_lower_version(asset.old_versions[-1].version, product_spec['version']):
                    raise ProductError('The provided version is not higher that the previous one')

                # Attach new info
                asset.version = product_spec['version']
                asset.save()

                # Release asset lock
                lock.unlock_document()
    def _get_upgrading_asset(self, asset_t, url, product_id):
        asset_type, assets = self._get_asset_resources(asset_t, url, None,
                                                       product_id)

        if not len(assets):
            raise ProductError(
                'The URL specified in the location characteristic does not point to a valid digital asset'
            )

        asset = assets[0]

        # Lock the access to the asset
        lock = DocumentLock('wstore_resource', asset.pk, 'asset')
        lock.wait_document()

        asset = Resource.objects.get(pk=asset.pk)

        # Check that the asset is in upgrading state
        if asset.state != 'upgrading':
            raise ProductError(
                'There is not a new version of the specified digital asset')

        if asset.product_id != product_id:
            raise ProductError(
                'The specified digital asset is included in other product spec'
            )

        return asset, lock
    def parse_characteristics(self, product_spec):
        expected_chars = {
            'asset type': [],
            'media type': [],
            'location': [],
            'asset': []
        }

        asset_type = None
        media_type = None
        location = None
        asset_id = None

        if 'productSpecCharacteristic' in product_spec:
            terms = []

            # Extract the needed characteristics for processing digital assets
            is_digital = False
            for char in product_spec['productSpecCharacteristic']:
                if char['name'].lower() in expected_chars:
                    is_digital = True
                    expected_chars[char['name'].lower()].append(
                        self._get_characteristic_value(char))

                if char['name'].lower() == 'license':
                    terms.append(self._get_characteristic_value(char))

            for char_name in expected_chars:
                # Validate the existence of the characteristic
                if not len(expected_chars[char_name]) and is_digital:
                    raise ProductError(
                        'Digital product specifications must contain a ' +
                        char_name + ' characteristic')

                # Validate that only a value has been provided
                if len(expected_chars[char_name]) > 1:
                    raise ProductError(
                        'The product specification must not contain more than one '
                        + char_name + ' characteristic')

            if len(terms) > 1:
                raise ProductError(
                    'The product specification must not contain more than one license characteristic'
                )

            self._has_terms = len(terms) > 0

            if is_digital:
                asset_type = expected_chars['asset type'][0]
                media_type = expected_chars['media type'][0]
                location = expected_chars['location'][0]
                asset_id = expected_chars['asset'][0]

        return asset_type, media_type, location, asset_id
    def _validate_product(self, provider, asset_t, media_type, url):

        asset_type, assets = self._get_asset_resouces(asset_t, url)

        if len(assets):
            # The asset is already registered
            asset = assets[0]

            if asset.product_id is not None:
                raise ConflictError(
                    'There is already an existing product specification defined for the given digital asset'
                )

            self._validate_product_characteristics(asset, provider, asset_t,
                                                   media_type)

            asset.has_terms = self._has_terms
            asset.save()
        else:
            # The asset is not yet included, this option is only valid for URL assets without metadata
            site = settings.SITE
            if 'FILE' in asset_type.formats and (
                ('URL' not in asset_type.formats) or
                ('URL' in asset_type.formats and url.startswith(site))):

                raise ProductError(
                    'The URL specified in the location characteristic does not point to a valid digital asset'
                )

            if asset_type.form:
                raise ProductError(
                    'Automatic creation of digital assets with expected metadata is not supported'
                )

            # Validate media type
            if len(asset_type.media_types) and media_type.lower() not in [
                    media.lower() for media in asset_type.media_types
            ]:
                raise ProductError(
                    'The media type characteristic included in the product specification is not valid for the given asset type'
                )

            # Create the new asset model
            asset = Resource.objects.create(has_terms=self._has_terms,
                                            resource_path='',
                                            download_link=url,
                                            provider=provider,
                                            content_type=media_type)

        # The asset model is included to the rollback list so if an exception is raised in the plugin post validation
        # the asset model would be deleted
        self.rollback_logger['models'].append(asset)

        return asset
Esempio n. 5
0
    def _validate_product_characteristics(self, asset, provider, asset_t, media_type):
        if asset.provider != provider:
            raise PermissionDenied('You are not authorized to use the digital asset specified in the location characteristic')

        if asset.resource_type != asset_t:
            raise ProductError('The specified asset type is different from the asset one')

        if asset.content_type.lower() != media_type.lower():
            raise ProductError('The provided media type characteristic is different from the asset one')

        if asset.is_public:
            raise ProductError('It is not allowed to create products with public assets')
    def _get_asset_resources(self,
                             asset_t,
                             url,
                             provider_id=None,
                             prod_id=None):
        # Search the asset type
        asset_type = ResourcePlugin.objects.get(name=asset_t)

        # Validate location format
        if not is_valid_url(url):
            raise ProductError(
                'The location characteristic included in the product specification is not a valid URL'
            )

        # Use the location to retrieve the attached asset
        if not (provider_id is None):
            assets = Resource.objects.filter(download_link=url,
                                             provider=provider_id)
        elif not (prod_id is None):
            assets = Resource.objects.filter(download_link=url,
                                             product_id=prod_id)
        else:
            assets = Resource.objects.filter(download_link=url)

        return asset_type, assets
Esempio n. 7
0
    def _build_bundle(self, provider, product_spec):
        if 'bundledProductSpecification' not in product_spec or not len(product_spec['bundledProductSpecification']) > 1:
            raise ProductError('A product spec bundle must contain at least two bundled product specs')

        assets = self._extract_digital_assets(product_spec['bundledProductSpecification'])

        if len(assets) and len(assets) != len(product_spec['bundledProductSpecification']):
            raise ProductError('Mixed product bundles are not allowed. All bundled products must be digital or physical')

        if len(assets):
            Resource.objects.create(
                has_terms=self._has_terms,
                resource_path='',
                download_link='',
                provider=provider,
                content_type='bundle',
                bundled_assets=assets
            )
def _get_plugin_model(name):
    try:
        plugin_model = ResourcePlugin.objects.get(name=name)
    except:
        # Validate resource type
        raise ProductError(
            'The given product specification contains a not supported asset type: '
            + name)

    return plugin_model
Esempio n. 9
0
    def validate_creation(self, provider, product_spec):
        # Extract product needed characteristics
        asset_t, media_type, url, asset_id = self.parse_characteristics(product_spec)
        is_digital = asset_t is not None and media_type is not None and url is not None

        # Product spec bundles are intended for creating composed products, it cannot contain its own asset
        if product_spec['isBundle'] and is_digital:
            raise ProductError('Product spec bundles cannot define digital assets')

        if not product_spec['isBundle'] and is_digital:
            # Process the new digital product
            self._validate_product(provider, asset_t, media_type, url, asset_id)

        elif product_spec['isBundle'] and not is_digital:
            # The product bundle may contain digital products already registered
            self._build_bundle(provider, product_spec)
 def _prod_val_product_error(self):
     self.validator_instance.validate.side_effect = ProductError('Missing product information')
    def _get_characteristic_value(self, characteristic):
        if len(characteristic['productSpecCharacteristicValue']) > 1:
            raise ProductError('The characteristic ' + characteristic['name'] +
                               ' must not contain multiple values')

        return characteristic['productSpecCharacteristicValue'][0]['value']
    def _validate_product(self, provider, asset_t, media_type, url):
        # Search the asset type
        asset_type = ResourcePlugin.objects.get(name=asset_t)

        # Validate media type
        if len(asset_type.media_types
               ) and media_type not in asset_type.media_types:
            raise ProductError(
                'The media type characteristic included in the product specification is not valid for the given asset type'
            )

        # Validate location format
        if not is_valid_url(url):
            raise ProductError(
                'The location characteristic included in the product specification is not a valid URL'
            )

        site = Context.objects.all()[0].site

        # If the asset is a file it must have been uploaded
        if 'FILE' in asset_type.formats and (
            ('URL' not in asset_type.formats) or
            ('URL' in asset_type.formats and url.startswith(site.domain))):

            try:
                asset = Resource.objects.get(download_link=url)
            except:
                raise ProductError(
                    'The URL specified in the location characteristic does not point to a valid digital asset'
                )

            if asset.provider != provider:
                raise PermissionDenied(
                    'You are not authorized to use the digital asset specified in the location characteristic'
                )

            if asset.content_type != media_type.lower():
                raise ProductError(
                    'The specified media type characteristic is different from the one of the provided digital asset'
                )

            asset.has_terms = self._has_terms
            asset.save()
        else:
            # If the asset is an URL and the resource model is created, that means that
            # the asset have been already included in another product
            resources = Resource.objects.filter(download_link=url)
            error = False
            for res in resources:
                # The asset has been attached so it already exists
                if res.product_id:
                    error = True
                else:
                    res.delete()

            if error:
                raise ProductError(
                    'There is already an existing product specification defined for the given digital asset'
                )

            # Create the new asset model
            asset = Resource.objects.create(has_terms=self._has_terms,
                                            resource_path='',
                                            download_link=url,
                                            provider=provider,
                                            content_type=media_type)
            self.rollback_logger['models'].append(asset)

        return asset