def _validate_resource_info(provider, data, file_=None): # Check if the resource already exists existing = True current_organization = provider.userprofile.current_organization try: Resource.objects.get(name=data['name'], provider=current_organization) except: existing = False if existing: raise ConflictError('The resource ' + data['name'] + ' already exists. Please upgrade the resource if you want to provide new content') # Check contents if 'name' not in data or 'version' not in data or\ 'description' not in data or 'content_type' not in data or\ 'resource_type' not in data: raise ValueError('Invalid request: Missing required field') # Create version object to validate resource version format Version(data['version']) # Check name format if not is_valid_id(data['name']): raise ValueError('Invalid name format') return ({ 'name': data['name'], 'version': data['version'], 'description': data['description'], 'content_type': data['content_type'], 'resource_type': data['resource_type'], 'open': data.get('open', False) }, current_organization)
def create(self, request): if not request.user.is_staff: # Only an admin could register a new repository return build_response(request, 403, 'Forbidden') # Get request info name = None host = None try: content = json.loads(request.raw_post_data) name = content['name'] host = content['host'] except: msg = "Request body is not valid JSON data" return build_response(request, 400, msg) # Check data formats if not is_valid_id(name): return build_response(request, 400, 'Invalid name format') if not is_valid_url(host): return build_response(request, 400, 'Invalid URL format') # Register repository try: register_repository(name, host) except Exception, e: return build_response(request, 400, e.message)
def create(self, request): if not request.user.is_staff: # Only an admin could register the store in a marketplace return build_response(request, 403, 'Forbidden') name = None host = None # Get contents from the request try: content = json.loads(request.raw_post_data) name = content['name'] host = content['host'] except: msg = "Request body is not valid JSON data" return build_response(request, 400, msg) # Check data formats if not is_valid_id(name): return build_response(request, 400, 'Invalid name format') if not is_valid_url(host): return build_response(request, 400, 'Invalid URL format') code = 201 msg = 'Created' try: # Register the store in the selected marketplace register_on_market(name, host, get_current_site(request).domain) except Exception, e: if e.message == 'Bad Gateway': code = 502 msg = e.message else: code = 400 msg = 'Bad request'
def _validate_plugin_form(self, form_info): """ Validates the structure of the form definition of a plugin included in the package.json file """ reason = None valid_types = ['text', 'textarea', 'checkbox', 'select'] for k, v in form_info.iteritems(): # Validate component if not isinstance(v, dict): reason = 'Invalid form field: ' + k + ' entry is not an object' break # Validate type value if 'type' not in v: reason = 'Invalid form field: Missing type in ' + k + ' entry' break if not v['type'] in valid_types: reason = 'Invalid form field: type ' + v['type'] + ' in ' + k + ' entry is not a valid type' break # Validate name format if not is_valid_id(k): reason = 'Invalid form field: ' + k + ' is not a valid name' break # Validate specific fields if v['type'] == 'checkbox' and 'default' in v and not isinstance(v['default'], bool): reason = 'Invalid form field: default field in ' + k + ' entry must be a boolean' break return reason
def create(self, request): if not request.user.is_staff: return build_response(request, 403, 'Forbidden') try: data = json.loads(request.raw_post_data) if not len(data['name']) > 4 or not is_valid_id(data['name']): raise Exception('Invalid name format') if 'notification_url' in data: if data['notification_url'] and not is_valid_url(data['notification_url']): raise Exception('Invalid notification URL format') else: data['notification_url'] = '' tax_address = {} if 'tax_address' in data: tax_address = { 'street': data['tax_address']['street'], 'postal': data['tax_address']['postal'], 'city': data['tax_address']['city'], 'country': data['tax_address']['country'] } payment_info = {} if 'payment_info' in data: if not is_valid_credit_card(data['payment_info']['number']): raise Exception() payment_info = { 'type': data['payment_info']['type'], 'number': data['payment_info']['number'], 'expire_month': data['payment_info']['expire_month'], 'expire_year': data['payment_info']['expire_year'], 'cvv2': data['payment_info']['cvv2'] } Organization.objects.create( name=data['name'], notification_url=data['notification_url'], tax_address=tax_address, payment_info=payment_info, private=False ) except Exception as e: msg = e.message if not msg.startswith('Invalid'): msg = 'Invalid content' return build_response(request, 400, msg) return build_response(request, 201, 'Created')
def create(self, request): # Check if the user is an admin if not request.user.is_staff: return build_response(request, 403, 'Forbidden') # Get data data = json.loads(request.raw_post_data) if not 'currency' in data: return build_response(request, 400, 'Invalid JSON content') # Check currency regex if not is_valid_id(data['currency']): return build_response(request, 400, 'Invalid currency format') # Get the context context = Context.objects.all()[0] # Check if the allowed_currencies list is empty first = False if not 'allowed' in context.allowed_currencies: first = True context.allowed_currencies['allowed'] = [] error = False # Check that the new currency is not already included for curr in context.allowed_currencies['allowed']: if curr['currency'].lower() == data['currency'].lower(): error = True break if error: return build_response(request, 400, 'The currency already exists') # Check if it is the default currency if ('default' in data and data['default']) or first: # Note the this will override previous default currency context.allowed_currencies['default'] = data['currency'] # Include new currency context.allowed_currencies['allowed'].append({ 'currency': data['currency'], 'in_use': False }) context.save() return build_response(request, 201, 'Created')
def create(self, request): # Check if the user is an admin if not request.user.is_staff: return build_response(request, 403, 'Forbidden') # Get data data = json.loads(request.body) if not 'currency' in data: return build_response(request, 400, 'Invalid JSON content') # Check currency regex if not is_valid_id(data['currency']): return build_response(request, 400, 'Invalid currency format') # Get the context context = Context.objects.all()[0] # Check if the allowed_currencies list is empty first = False if not 'allowed' in context.allowed_currencies: first = True context.allowed_currencies['allowed'] = [] error = False # Check that the new currency is not already included for curr in context.allowed_currencies['allowed']: if curr['currency'].lower() == data['currency'].lower(): error = True break if error: return build_response(request, 400, 'The currency already exists') # Check if it is the default currency if ('default' in data and data['default']) or first: # Note the this will override previous default currency context.allowed_currencies['default'] = data['currency'] # Include new currency context.allowed_currencies['allowed'].append({ 'currency': data['currency'], 'in_use': False }) context.save() return build_response(request, 201, 'Created')
def _validate_resource_info(provider, data, file_=None): # Check if the resource already exists existing = True current_organization = provider.userprofile.current_organization try: Resource.objects.get(name=data['name'], provider=current_organization) except: existing = False if existing: raise ConflictError( 'The resource ' + data['name'] + ' already exists. Please upgrade the resource if you want to provide new content' ) # Check contents if 'name' not in data or 'version' not in data or\ 'description' not in data or 'content_type' not in data or\ 'resource_type' not in data: raise ValueError('Invalid request: Missing required field') # Create version object to validate resource version format Version(data['version']) # Check name format if not is_valid_id(data['name']): raise ValueError('Invalid name format') return ({ 'name': data['name'], 'version': data['version'], 'description': data['description'], 'content_type': data['content_type'], 'resource_type': data['resource_type'], 'open': data.get('open', False) }, current_organization)
def create(self, request): if not request.user.is_staff: # Only an admin can register the store in a marketplace return build_response(request, 403, 'You are not allowed to register WStore in a Marketplace') name = None host = None api_version = None # Get contents from the request try: content = json.loads(request.raw_post_data) name = content['name'] host = content['host'] api_version = content['api_version'] except: msg = "Request body is not valid JSON data" return build_response(request, 400, msg) # Check data formats if not is_valid_id(name): return build_response(request, 400, 'Invalid name format') if not is_valid_url(host): return build_response(request, 400, 'Invalid URL format') if not api_version.isdigit(): return build_response(request, 400, 'Invalid API version') api_version = int(api_version) if api_version != 1 and api_version != 2: return build_response(request, 400, 'Invalid API version') credentials = None # Validate credentials if required if api_version == 1 or not settings.OILAUTH: if 'credentials' not in content: return build_response(request, 400, 'Missing required field credentials') if 'username' not in content['credentials']: return build_response(request, 400, 'Missing required field username in credentials') if 'passwd' not in content['credentials']: return build_response(request, 400, 'Missing required field passwd in credentials') credentials = content['credentials'] code = 201 msg = 'Created' try: # Register the store in the selected marketplace register_on_market(request.user, name, host, api_version, credentials, get_current_site(request).domain) except HTTPError: code = 502 msg = "The Marketplace has failed registering the store" except ConflictError as e: code = 409 msg = unicode(e) except Exception as e: code = 500 msg = unicode(e) return build_response(request, code, msg)
def create_offering(provider, json_data): profile = provider.userprofile data = {} if not 'name' in json_data or not 'version' in json_data: raise ValueError('Missing required fields') data['name'] = json_data['name'] data['version'] = json_data['version'] if not re.match(re.compile(r'^(?:[1-9]\d*\.|0\.)*(?:[1-9]\d*|0)$'), data['version']): raise ValueError('Invalid version format') if not is_valid_id(data['name']): raise ValueError('Invalid name format') # Get organization organization = profile.current_organization # Check if the offering already exists existing = True try: Offering.objects.get(name=data['name'], owner_organization=organization, version=data['version']) except: existing = False if existing: raise Exception('The offering already exists') # Check if the version of the offering is lower than an existing one offerings = Offering.objects.filter(owner_organization=organization, name=data['name']) for off in offerings: if is_lower_version(data['version'], off.version): raise ValueError('A bigger version of the current offering exists') is_open = json_data.get('open', False) # If using the idm, get the applications from the request if settings.OILAUTH: # Validate application structure data['applications'] = [] for app in json_data['applications']: data['applications'].append({ 'name': app['name'], 'url': app['url'], 'id': app['id'], 'description': app['description'] }) data['related_images'] = [] # Check the URL to notify the provider notification_url = '' if 'notification_url' in json_data: if json_data['notification_url'] == 'default': notification_url = organization.notification_url if not notification_url: raise ValueError('There is not a default notification URL defined for the organization ' + organization.name + '. To configure a default notification URL provide it in the settings menu') else: # Check the notification URL if not is_valid_url(json_data['notification_url']): raise ValueError("Invalid notification URL format: It doesn't seem to be an URL") notification_url = json_data['notification_url'] # Create the directory for app media dir_name = organization.name + '__' + data['name'] + '__' + data['version'] path = os.path.join(settings.MEDIA_ROOT, dir_name) os.makedirs(path) if not 'image' in json_data: raise ValueError('Missing required field: Logo') if not isinstance(json_data['image'], dict): raise TypeError('Invalid image type') image = json_data['image'] if not 'name' in image or not 'data' in image: raise ValueError('Missing required field in image') # Save the application image or logo f = open(os.path.join(path, image['name']), "wb") dec = base64.b64decode(image['data']) f.write(dec) f.close() data['image_url'] = settings.MEDIA_URL + dir_name + '/' + image['name'] # Save screen shots if 'related_images' in json_data: for image in json_data['related_images']: # images must be encoded in base64 format f = open(os.path.join(path, image['name']), "wb") dec = base64.b64decode(image['data']) f.write(dec) f.close() data['related_images'].append(settings.MEDIA_URL + dir_name + '/' + image['name']) # Save USDL document # If the USDL itself is provided if 'offering_description' in json_data: usdl_info = json_data['offering_description'] repository = Repository.objects.get(name=json_data['repository']) repository_adaptor = RepositoryAdaptor(repository.host, 'storeOfferingCollection') offering_id = organization.name + '__' + data['name'] + '__' + data['version'] usdl = usdl_info['data'] data['description_url'] = repository_adaptor.upload(usdl_info['content_type'], usdl_info['data'], name=offering_id) # If the USDL is already uploaded in the repository elif 'description_url' in json_data: # Check that the link to USDL is unique since could be used to # purchase offerings from Marketplace usdl_info = {} usdl_url = json_data['description_url'] off = Offering.objects.filter(description_url=usdl_url) if len(off) != 0: raise ValueError('The provided USDL description is already registered') # Download the USDL from the repository repository_adaptor = RepositoryAdaptor(usdl_url) accept = "text/plain; application/rdf+xml; text/turtle; text/n3" usdl = repository_adaptor.download(content_type=accept) usdl_info['content_type'] = usdl['content_type'] usdl = usdl['data'] data['description_url'] = usdl_url # If the USDL is going to be created elif 'offering_info' in json_data: _validate_offering_info(json_data['offering_info']) offering_info = json_data['offering_info'] offering_info['image_url'] = data['image_url'] offering_info['name'] = data['name'] repository = Repository.objects.get(name=json_data['repository']) offering_info['base_uri'] = repository.host usdl = _create_basic_usdl(offering_info) usdl_info = { 'content_type': 'application/rdf+xml' } repository_adaptor = RepositoryAdaptor(repository.host, 'storeOfferingCollection') offering_id = organization.name + '__' + data['name'] + '__' + data['version'] data['description_url'] = repository_adaptor.upload(usdl_info['content_type'], usdl, name=offering_id) else: raise Exception('No USDL description provided') # Validate the USDL data['open'] = is_open data['organization'] = organization valid = validate_usdl(usdl, usdl_info['content_type'], data) if not valid[0]: raise Exception(valid[1]) # Check new currencies used if len(valid) > 2: new_curr = valid[2] # Set the currency as used cont = Context.objects.all()[0] currency = None # Search the currency for c in cont.allowed_currencies['allowed']: if c['currency'].lower() == new_curr.lower(): currency = c break cont.allowed_currencies['allowed'].remove(currency) currency['in_use'] = True cont.allowed_currencies['allowed'].append(currency) cont.save() # Serialize and store USDL info in json-ld format graph = rdflib.Graph() rdf_format = usdl_info['content_type'] if rdf_format == 'text/turtle' or rdf_format == 'text/plain': rdf_format = 'n3' elif rdf_format == 'application/json': rdf_format = 'json-ld' graph.parse(data=usdl, format=rdf_format) data['offering_description'] = graph.serialize(format='json-ld', auto_compact=True) # Create the offering offering = Offering.objects.create( name=data['name'], owner_organization=organization, owner_admin_user=provider, version=data['version'], state='uploaded', description_url=data['description_url'], resources=[], comments=[], tags=[], image_url=data['image_url'], related_images=data['related_images'], offering_description=json.loads(data['offering_description']), notification_url=notification_url, creation_date=datetime.now(), open=is_open ) if settings.OILAUTH: offering.applications = data['applications'] offering.save() if 'resources' in json_data and len(json_data['resources']) > 0: bind_resources(offering, json_data['resources'], profile.user) # Load offering document to the search index index_path = os.path.join(settings.BASEDIR, 'wstore') index_path = os.path.join(index_path, 'search') index_path = os.path.join(index_path, 'indexes') search_engine = SearchEngine(index_path) search_engine.create_index(offering)
def create_offering(provider, data): """ Creates a new offering including the media files and the repository uploads """ profile = provider.userprofile # Validate basic fields if 'name' not in data or 'version' not in data or 'offering_description' not in data \ or 'image' not in data: missing_fields = '' if 'name' not in data: missing_fields += ' name' if 'version' not in data: missing_fields += ' version' if 'offering_description' not in data: missing_fields += ' offering_description' if 'image' not in data: missing_fields += ' image' raise ValueError('Missing required fields:' + missing_fields) if not re.match(re.compile(r'^(?:[1-9]\d*\.|0\.)*(?:[1-9]\d*|0)$'), data['version']): raise ValueError('Invalid version format') if not is_valid_id(data['name']): raise ValueError('Invalid name format') # Get organization organization = profile.current_organization # Check if the offering already exists if len(Offering.objects.filter(name=data['name'], owner_organization=organization, version=data['version'])) > 0: raise ConflictError('The offering ' + data['name'] + ' version ' + data['version'] + ' already exists') # Check if the version of the offering is lower than an existing one offerings = Offering.objects.filter(owner_organization=organization, name=data['name']) for off in offerings: if is_lower_version(data['version'], off.version): raise ValueError('A bigger version of the current offering exists') is_open = data.get('open', False) # If using the idm, get the applications from the request if settings.OILAUTH and 'applications' in data: # Validate application structure for app in data['applications']: if 'name' not in app or 'url' not in app or 'id' not in app or 'description' not in app: raise ValueError('Missing a required field in application definition') # Check the URL to notify the provider notification_url = '' if 'notification_url' in data: if data['notification_url'] == 'default': notification_url = organization.notification_url if not notification_url: raise ValueError('There is not a default notification URL defined for the organization ' + organization.name + '. To configure a default notification URL provide it in the settings menu') else: # Check the notification URL if not is_valid_url(data['notification_url']): raise ValueError("Invalid notification URL format: It doesn't seem to be an URL") notification_url = data['notification_url'] # Create the directory for app media dir_name = organization.name + '__' + data['name'] + '__' + data['version'] path = os.path.join(settings.MEDIA_ROOT, dir_name) os.makedirs(path) # Validate image format if not isinstance(data['image'], dict): raise TypeError('Invalid image type') data['image_url'] = _create_image(dir_name, path, data['image']) # Save screen shots screenshots = [] if 'related_images' in data: for image in data['related_images']: screenshots.append(_create_image(dir_name, path, image)) else: data['related_images'] = [] # Validate the USDL data['open'] = is_open data['organization'] = organization # Create offering USDL offering_info = deepcopy(data['offering_description']) offering_info['image_url'] = data['image_url'] offering_info['name'] = data['name'] offering_info['version'] = data['version'] offering_info['organization'] = organization.name offering_info['base_id'] = 'pk' created = datetime.now() offering_info['created'] = unicode(created) offering_info['modified'] = unicode(created) data['offering_description']['modified'] = unicode(created) usdl_generator = USDLGenerator() usdl_generator.validate_info(offering_info, organization, open_=is_open) # Create the offering offering = Offering( name=data['name'], owner_organization=organization, owner_admin_user=provider, version=data['version'], state='uploaded', resources=[], comments=[], tags=[], image_url=data['image_url'], related_images=screenshots, notification_url=notification_url, creation_date=created, open=is_open, offering_description=data['offering_description'] ) if settings.OILAUTH and 'applications' in data: offering.applications = data['applications'] offering.save() offering.offering_description['base_id'] = offering.pk offering.save() if 'resources' in data and len(data['resources']) > 0: bind_resources(offering, data['resources'], profile.user) # Load offering document to the search index index_path = os.path.join(settings.BASEDIR, 'wstore') index_path = os.path.join(index_path, 'search') index_path = os.path.join(index_path, 'indexes') search_engine = SearchEngine(index_path) search_engine.create_index(offering)
def create(self, request): if settings.OILAUTH: return build_response( request, 403, 'It is not possible to create users (use Account enabler instead)' ) if not request.user.is_staff: return build_response(request, 403, 'Forbidden') data = json.loads(request.raw_post_data) # Validate Info if (not 'roles' in data) or (not 'username' in data) or (not 'first_name') in data \ or (not 'last_name' in data) or (not 'password' in data): return build_response(request, 400, 'Missing required field') # Check username format if not len(data['username']) > 4 or not is_valid_id(data['username']): return build_response(request, 400, 'Invalid username format') # Create the user try: user = User.objects.create(username=data['username'], first_name=data['first_name'], last_name=data['last_name']) # Create the password user.set_password(data['password']) if 'admin' in data['roles']: user.is_staff = True user.save() # Get the user profile user_profile = UserProfile.objects.get(user=user) user_profile.complete_name = data['first_name'] + ' ' + data[ 'last_name'] if 'notification_url' in data: # Check notification URL format if data['notification_url'] and not is_valid_url( data['notification_url']): raise Exception('Invalid notification URL format') user_profile.current_organization.notification_url = data[ 'notification_url'] user_profile.current_organization.save() if 'provider' in data['roles']: # Append the provider role to the user organization # The user profile is just created so only the private organization exists org = user_profile.organizations[0] org['roles'].append('provider') user_profile.save() user_profile.organizations = [org] if 'tax_address' in data: user_profile.tax_address = { 'street': data['tax_address']['street'], 'postal': data['tax_address']['postal'], 'city': data['tax_address']['city'], 'country': data['tax_address']['country'] } if 'payment_info' in data: if not is_valid_credit_card(data['payment_info']['number']): raise Exception() user_profile.payment_info = { 'type': data['payment_info']['type'], 'number': data['payment_info']['number'], 'expire_month': data['payment_info']['expire_month'], 'expire_year': data['payment_info']['expire_year'], 'cvv2': data['payment_info']['cvv2'] } user_profile.save() except Exception as e: return build_response(request, 400, unicode(e)) return build_response(request, 201, 'Created')
def register_resource(provider, data, file_=None): # Check if the resource already exists existing = True current_organization = provider.userprofile.current_organization try: Resource.objects.get(name=data["name"], provider=current_organization) except: existing = False if existing: raise ValueError( "The resource " + data["name"] + " already exists. Please upgrade the resource if you want to provide new content" ) # Check contents if not "name" in data or not "version" in data or not "description" in data or not "content_type" in data: raise ValueError("Invalid request: Missing required field") # Check version format if not re.match(re.compile(r"^(?:[1-9]\d*\.|0\.)*(?:[1-9]\d*|0)$"), data["version"]): raise ValueError("Invalid version format") # Check name format if not is_valid_id(data["name"]): raise ValueError("Invalid name format") resource_data = { "name": data["name"], "version": data["version"], "description": data["description"], "content_type": data["content_type"], } if not file_: if "content" in data: resource_data["content_path"] = _save_resource_file( current_organization.name, data["name"], data["version"], data["content"] ) resource_data["link"] = "" elif "link" in data: # Add the download link # Check link format if not is_valid_url(data["link"]): raise ValueError("Invalid resource link format") resource_data["link"] = data["link"] resource_data["content_path"] = "" else: raise ValueError("Invalid request: Missing resource content") else: resource_data["content_path"] = _save_resource_file( current_organization.name, data["name"], data["version"], file_ ) resource_data["link"] = "" Resource.objects.create( name=resource_data["name"], provider=current_organization, version=resource_data["version"], description=resource_data["description"], download_link=resource_data["link"], resource_path=resource_data["content_path"], content_type=resource_data["content_type"], state="created", open=data.get("open", False), )
def create(self, request): # Only the admin can register new RSS instances if not request.user.is_staff: return build_response(request, 403, 'Forbidden') data = json.loads(request.raw_post_data) if not 'name' in data or not 'host': return build_response(request, 400, 'Invalid JSON content') # Check name regex if not is_valid_id(data['name']): return build_response(request, 400, 'Invalid name format') # Check url regex if not is_valid_url(data['host']): return build_response(request, 400, 'Invalid URL format') # Check if the information provided is not already registered if len(RSS.objects.filter(name=data['name'])) > 0 or \ len(RSS.objects.filter(host=data['host'])) > 0: return build_response(request, 400, 'Invalid JSON content') limits = {} cont = Context.objects.all()[0] # Check request limits if 'limits' in data: try: limits = _check_limits(data['limits']) except Exception as e: return build_response(request, 400, e.message) if not len(limits): # Set default limits limits = { 'currency': cont.allowed_currencies['default'], 'perTransaction': 10000, 'weekly': 100000, 'daily': 10000, 'monthly': 100000 } # Create the new entry rss = RSS.objects.create( name=data['name'], host=data['host'], expenditure_limits=limits) exp_manager = ExpenditureManager(rss, request.user.userprofile.access_token) # Create default expenditure limits call_result = _make_expenditure_request(exp_manager, exp_manager.set_provider_limit, request.user) if call_result[0]: # Remove created RSS entry rss.delete() # Return error response return build_response(request, call_result[1], call_result[2]) # The request has been success so the used credentials are valid # Store the credentials for future access rss.access_token = request.user.userprofile.access_token rss.refresh_token = request.user.userprofile.refresh_token rss.save() return build_response(request, 201, 'Created')
def create(self, request): if not request.user.is_active: return build_response(request, 403, 'The user has not been activated') try: data = json.loads(request.raw_post_data) if 'name' not in data: raise Exception('Invalid JSON content') organization_registered = Organization.objects.filter( name=data['name']) if len(organization_registered) > 0: raise Exception('The ' + data['name'] + ' organization is already registered.') if not len(data['name']) > 4 or not is_valid_id(data['name']): raise Exception('Enter a valid name.') if 'notification_url' in data: if data['notification_url'] and not is_valid_url( data['notification_url']): raise Exception('Enter a valid URL') else: data['notification_url'] = '' tax_address = {} if 'tax_address' in data: tax_address = { 'street': data['tax_address']['street'], 'postal': data['tax_address']['postal'], 'city': data['tax_address']['city'], 'country': data['tax_address']['country'] } payment_info = {} if 'payment_info' in data: if not is_valid_credit_card(data['payment_info']['number']): raise Exception('Invalid credit card info') payment_info = { 'type': data['payment_info']['type'], 'number': data['payment_info']['number'], 'expire_month': data['payment_info']['expire_month'], 'expire_year': data['payment_info']['expire_year'], 'cvv2': data['payment_info']['cvv2'] } Organization.objects.create( name=data['name'], notification_url=data['notification_url'], tax_address=tax_address, payment_info=payment_info, private=False) user_included = False if not request.user.is_staff or (request.user.is_staff and 'is_user' in \ data and data['is_user'] == True): user_included = True # Include the new user, if the user is not admin include the user # If the user is an admin, include it depending on if she has created # the organization as an user if user_included: user = request.user organization = Organization.objects.get(name=data['name']) user.userprofile.organizations.append({ 'organization': organization.pk, 'roles': [] }) user.userprofile.save() organization.managers.append(user.pk) organization.save() except Exception as e: msg = 'Invalid JSON content' if e.message: msg = e.message return build_response(request, 400, msg) return build_response(request, 201, 'Created')
def register_resource(provider, data, file_=None): # Check if the resource already exists existing = True current_organization = provider.userprofile.current_organization try: Resource.objects.get(name=data['name'], provider=current_organization, version=data['version']) except: existing = False if existing: raise Exception('The resource already exists') if not re.match(re.compile(r'^(?:[1-9]\d*\.|0\.)*(?:[1-9]\d*|0)$'), data['version']): raise Exception('Invalid version format') if not is_valid_id(data['name']): raise Exception('Invalid name format') resource_data = { 'name': data['name'], 'version': data['version'], 'description': data['description'], 'content_type': data['content_type'] } if file_ is None: if 'content' in data: resource = data['content'] # Check file name format if not is_valid_file(resource['name']): raise Exception('Invalid file name format: Unsupported character') #decode the content and save the media file file_name = current_organization.name + '__' + data['name'] + '__' + data['version'] + '__' + resource['name'] path = os.path.join(settings.MEDIA_ROOT, 'resources') file_path = os.path.join(path, file_name) f = open(file_path, "wb") dec = base64.b64decode(resource['data']) f.write(dec) f.close() resource_data['content_path'] = settings.MEDIA_URL + 'resources/' + file_name resource_data['link'] = '' elif 'link' in data: # Add the download link # Check link format if not is_valid_url(data['link']): raise Exception('Invalid Resource link format') resource_data['link'] = data['link'] resource_data['content_path'] = '' else: #decode the content and save the media file # Check file name format if not is_valid_file(file_.name): raise Exception('Invalid file name format: Unsupported character') file_name = current_organization.name + '__' + data['name'] + '__' + data['version'] + '__' + file_.name path = os.path.join(settings.MEDIA_ROOT, 'resources') file_path = os.path.join(path, file_name) f = open(file_path, "wb") f.write(file_.read()) f.close() resource_data['content_path'] = settings.MEDIA_URL + 'resources/' + file_name resource_data['link'] = '' Resource.objects.create( name=resource_data['name'], provider=current_organization, version=resource_data['version'], description=resource_data['description'], download_link=resource_data['link'], resource_path=resource_data['content_path'], content_type=resource_data['content_type'], state='created' )
def create(self, request): # Only the admin can register new RSS instances if not request.user.is_staff: return build_response(request, 403, 'Forbidden') data = json.loads(request.raw_post_data) if 'name' not in data or 'host' not in data or 'api_version' not in data: msg = 'RSS creation error: Missing a required field' if 'name' not in data: msg += ', name' if 'host' not in data: msg += ', host' if 'api_version' not in data: msg += ', api_version' return build_response(request, 400, msg) # Check name regex if not is_valid_id(data['name']): return build_response(request, 400, 'RSS creation error: Invalid name format') # Check url regex if not is_valid_url(data['host']): return build_response(request, 400, 'RSS creation error: Invalid URL format') # Check api_version format try: api_version = int(data['api_version']) except: return build_response(request, 400, 'RSS creation error: Invalid api_version format, must be an integer (1 or 2)') if api_version != 1 and api_version != 2: return build_response(request, 400, 'RSS creation error: Invalid api_version, must be 1 or 2') # Check if the information provided is not already registered if len(RSS.objects.all()) > 0: return build_response(request, 409, 'RSS creation error: There is a RSS instance already registered') limits = {} cont = Context.objects.all()[0] # Check request limits if 'limits' in data: try: limits = _check_limits(data['limits']) except Exception as e: return build_response(request, 400, unicode(e)) if not len(limits): # Set default limits limits = { 'currency': cont.allowed_currencies['default'], 'perTransaction': 10000, 'weekly': 100000, 'daily': 10000, 'monthly': 100000 } # Check revenue sharing models sharing_models = [] if 'models' in data: try: sharing_models = _check_revenue_models(data['models']) except Exception as e: return build_response(request, 400, unicode(e)) else: # Set default revenue models sharing_models = [{ 'class': 'single-payment', 'percentage': 10.0 }, { 'class': 'subscription', 'percentage': 20.0 }, { 'class': 'use', 'percentage': 30.0 }] # Build revenue models db_revenue_models = [] for model in sharing_models: db_revenue_models.append(RevenueModel( revenue_class=model['class'], percentage=Decimal(model['percentage']) )) if not data['host'].endswith('/'): data['host'] += '/' # Create the new entry rss = RSS.objects.create( name=data['name'], host=data['host'], api_version=api_version, expenditure_limits=limits, revenue_models=db_revenue_models, aggregator_id=request.user.email ) rss_factory = RSSManagerFactory(rss) # Create a new provider if needed if api_version == 2: prov_manager = rss_factory.get_provider_manager(request.user.userprofile.access_token) provider_info = { 'provider_id': settings.STORE_NAME.lower() + '-provider', 'provider_name': settings.STORE_NAME + '-Provider' } call_result = _make_rss_request(prov_manager, prov_manager.register_provider, request.user, provider_info) if call_result[0]: rss.delete() # Return error response return build_response(request, call_result[1], call_result[2]) exp_manager = rss_factory.get_expenditure_manager(request.user.userprofile.access_token) # Create default expenditure limits call_result = _make_rss_request(exp_manager, exp_manager.set_provider_limit, request.user) if call_result[0]: rss.delete() # Return error response return build_response(request, call_result[1], call_result[2]) # Create default revenue sharing models if api_version == 1: model_manager = rss_factory.get_model_manager(rss, request.user) model_created = False for model in sharing_models: def call_model_creation(): model_manager.create_revenue_model(model) call_result = _make_rss_request(model_manager, call_model_creation, request.user) if call_result[0] and not model_created: rss.delete() return build_response(request, call_result[1], call_result[2]) elif not call_result[0]: model_created = True # The request has been success so the used credentials are valid # Store the credentials for future access rss.access_token = request.user.userprofile.access_token rss.refresh_token = request.user.userprofile.refresh_token rss.save() return build_response(request, 201, 'Created')
def create(self, request): if not request.user.is_staff: # Only an admin can register the store in a marketplace return build_response( request, 403, 'You are not allowed to register WStore in a Marketplace') name = None host = None api_version = None # Get contents from the request try: content = json.loads(request.raw_post_data) name = content['name'] host = content['host'] api_version = content['api_version'] except: msg = "Request body is not valid JSON data" return build_response(request, 400, msg) # Check data formats if not is_valid_id(name): return build_response(request, 400, 'Invalid name format') if not is_valid_url(host): return build_response(request, 400, 'Invalid URL format') if not api_version.isdigit(): return build_response(request, 400, 'Invalid API version') api_version = int(api_version) if api_version != 1 and api_version != 2: return build_response(request, 400, 'Invalid API version') credentials = None # Validate credentials if required if api_version == 1 or not settings.OILAUTH: if 'credentials' not in content: return build_response(request, 400, 'Missing required field credentials') if 'username' not in content['credentials']: return build_response( request, 400, 'Missing required field username in credentials') if 'passwd' not in content['credentials']: return build_response( request, 400, 'Missing required field passwd in credentials') credentials = content['credentials'] code = 201 msg = 'Created' try: # Register the store in the selected marketplace register_on_market(request.user, name, host, api_version, credentials, get_current_site(request).domain) except HTTPError: code = 502 msg = "The Marketplace has failed registering the store" except ConflictError as e: code = 409 msg = unicode(e) except Exception as e: code = 500 msg = unicode(e) return build_response(request, code, msg)
def validate_plugin_info(self, plugin_info): """ Validates the structure of the package.json file of a plugin """ reason = None # Check plugin_info format if not isinstance(plugin_info, dict): reason = 'Plugin info must be a dict instance' # Validate structure if reason is None and "name" not in plugin_info: reason = 'Missing required field: name' # Validate types if reason is None and not isinstance(plugin_info['name'], str) and not isinstance(plugin_info['name'], unicode): reason = 'Plugin name must be an string' if reason is None and not is_valid_id(plugin_info['name']): reason = 'Invalid name format: invalid character' if reason is None and "author" not in plugin_info: reason = 'Missing required field: author' if reason is None and 'formats' not in plugin_info: reason = 'Missing required field: formats' if reason is None and 'module' not in plugin_info: reason = 'Missing required field: module' if reason is None and 'version' not in plugin_info: reason = 'Missing required field: version' if reason is None and not isinstance(plugin_info['author'], str) and not isinstance(plugin_info['author'], unicode): reason = 'Plugin author must be an string' if reason is None and not isinstance(plugin_info['formats'], list): reason = 'Plugin formats must be a list' # Validate formats if reason is None: valid_format, i = self._check_list_field(['FILE', 'URL'], plugin_info['formats']) if not valid_format or (i < 1 and i > 2): reason = 'Format must contain at least one format of: FILE, URL' # Validate overrides if reason is None and 'overrides' in plugin_info and not self._check_list_field(["NAME", "VERSION", "OPEN"], plugin_info['overrides'])[0]: reason = "Override values should be one of: NAME, VERSION and OPEN" if reason is None and 'media_types' in plugin_info and not isinstance(plugin_info['media_types'], list): reason = 'Plugin media_types must be a list' if reason is None and not isinstance(plugin_info['module'], str) and not isinstance(plugin_info['module'], unicode): reason = 'Plugin module must be an string' if reason is None and not is_valid_version(plugin_info['version']): reason = 'Invalid format in plugin version' if reason is None and 'form' in plugin_info: if not isinstance(plugin_info['form'], dict): reason = 'Invalid format in form field, must be an object' else: reason = self._validate_plugin_form(plugin_info['form']) return reason
def create(self, request): if not request.user.is_staff: # Only an admin could register a new repository return build_response(request, 403, 'You are not authorized to register a repository') # Get request info try: content = json.loads(request.raw_post_data) is_default = content.get('is_default', False) except: msg = "Request body is not valid JSON data" return build_response(request, 400, msg) if 'name' not in content: return build_response(request, 400, 'Missing required field: name') if 'host' not in content: return build_response(request, 400, 'Missing required field: host') if 'api_version' not in content: return build_response(request, 400, 'Missing required field: api_version') if 'offering_collection' not in content: return build_response(request, 400, 'Missing required field: offering_collection') if 'resource_collection' not in content: return build_response(request, 400, 'Missing required field: resource_collection') # Check data formats if not is_valid_id(content['name']): return build_response(request, 400, 'Invalid name format') if not is_valid_id(content['offering_collection']) or ' ' in content['offering_collection']: return build_response(request, 400, 'Invalid offering_collection format: Invalid character found') if not is_valid_id(content['resource_collection']) or ' ' in content['resource_collection']: return build_response(request, 400, 'Invalid resource_collection format: Invalid character found') if not is_valid_url(content['host']): return build_response(request, 400, 'Invalid URL format') if not content['api_version'].isdigit(): return build_response(request, 400, 'Invalid api_version format: must be an integer') api_version = int(content['api_version']) if api_version != 1 and api_version != 2: return build_response(request, 400, 'Invalid api_version: Only versions 1 and 2 are supported') # Register repository try: register_repository( content['name'], content['host'], content['offering_collection'], content['resource_collection'], api_version, is_default ) except ConflictError as e: return build_response(request, 409, unicode(e)) except Exception as e: return build_response(request, 500, unicode(e)) return build_response(request, 201, 'Created')
def _validate_plugin_form(self, form_info): """ Validates the structure of the form definition of a plugin included in the package.json file """ reason = None def _text_type(key, value, attrs): reasonStr = '' for attr in attrs: if attr in value and not (isinstance(value[attr], str) or isinstance(value[attr], unicode)): reasonStr += '\nInvalid form field: ' + attr + ' field in ' + key + ' entry must be an string' return reasonStr def _bool_type(key, value, attrs): reasonStr = '' for attr in attrs: if attr in value and not isinstance(value[attr], bool): reasonStr += '\nInvalid form field: ' + attr + ' field in ' + key + ' entry must be a boolean' return reasonStr def _validate_text_type(key, value): reasonStr = _text_type(key, value, ['default', 'placeholder', 'label']) reasonStr += _bool_type(key, value, ['mandatory']) return reasonStr if len(reasonStr) else None def _validate_checkbox_type(key, value): reasonStr = _text_type(key, value, ['label']) reasonStr += _bool_type(key, value, ['default', 'mandatory']) return reasonStr if len(reasonStr) else None def _validate_select_type(key, value): reasonStr = _text_type(key, value, ['default', 'label']) reasonStr += _bool_type(key, value, ['mandatory']) if 'options' not in value or not isinstance(value['options'], list) or not len(value['options']): reasonStr += '\nInvalid form field: Missing or invalid options in ' + k + ' field' else: for option in value['options']: if not isinstance(option, dict) or not 'text' in option or not 'value' in option: reasonStr += '\nInvalid form field: Invalid option in ' + k + ' field, wrong option type or missing field' else: reasonStr += _text_type(key, option, ['text', 'value']) return reasonStr if len(reasonStr) else None valid_types = { 'text': _validate_text_type, 'textarea': _validate_text_type, 'checkbox': _validate_checkbox_type, 'select': _validate_select_type } for k, v in form_info.iteritems(): # Validate component if not isinstance(v, dict): reason = 'Invalid form field: ' + k + ' entry is not an object' break # Validate type value if 'type' not in v: reason = 'Invalid form field: Missing type in ' + k + ' entry' break if not v['type'] in valid_types: reason = 'Invalid form field: type ' + v['type'] + ' in ' + k + ' entry is not a valid type' break # Validate name format if not is_valid_id(k): reason = 'Invalid form field: ' + k + ' is not a valid name' break # Validate specific fields reason = valid_types[v['type']](k, v) if reason is not None: break return reason
def create(self, request): if not request.user.is_active: return build_response(request, 403, 'The user has not been activated') try: data = json.loads(request.raw_post_data) if 'name' not in data: raise Exception('Invalid JSON content') organization_registered = Organization.objects.filter(name=data['name']) if len(organization_registered) > 0: raise Exception('The ' + data['name'] + ' organization is already registered.') if not len(data['name']) > 4 or not is_valid_id(data['name']): raise Exception('Enter a valid name.') if 'notification_url' in data: if data['notification_url'] and not is_valid_url(data['notification_url']): raise Exception('Enter a valid URL') else: data['notification_url'] = '' tax_address = {} if 'tax_address' in data: tax_address = { 'street': data['tax_address']['street'], 'postal': data['tax_address']['postal'], 'city': data['tax_address']['city'], 'country': data['tax_address']['country'] } payment_info = {} if 'payment_info' in data: if not is_valid_credit_card(data['payment_info']['number']): raise Exception('Invalid credit card info') payment_info = { 'type': data['payment_info']['type'], 'number': data['payment_info']['number'], 'expire_month': data['payment_info']['expire_month'], 'expire_year': data['payment_info']['expire_year'], 'cvv2': data['payment_info']['cvv2'] } Organization.objects.create( name=data['name'], notification_url=data['notification_url'], tax_address=tax_address, payment_info=payment_info, private=False ) user_included = False if not request.user.is_staff or (request.user.is_staff and 'is_user' in \ data and data['is_user'] == True): user_included = True # Include the new user, if the user is not admin include the user # If the user is an admin, include it depending on if she has created # the organization as an user if user_included: user = request.user organization = Organization.objects.get(name=data['name']) user.userprofile.organizations.append({ 'organization': organization.pk, 'roles': [] }) user.userprofile.save() organization.managers.append(user.pk) organization.save() except Exception as e: msg = 'Invalid JSON content' if e.message: msg = e.message return build_response(request, 400, msg) return build_response(request, 201, 'Created')
def create(self, request): if settings.OILAUTH: return build_response(request, 403, 'It is not possible to create users (use Account enabler instead)') if not request.user.is_staff: return build_response(request, 403, 'Forbidden') data = json.loads(request.raw_post_data) # Validate Info if (not 'roles' in data) or (not 'username' in data) or (not 'first_name') in data \ or (not 'last_name' in data) or (not 'password' in data): return build_response(request, 400, 'Missing required field') # Check username format if not len(data['username']) > 4 or not is_valid_id(data['username']): return build_response(request, 400, 'Invalid username format') # Create the user try: user = User.objects.create(username=data['username'], first_name=data['first_name'], last_name=data['last_name']) # Create the password user.set_password(data['password']) if 'admin' in data['roles']: user.is_staff = True user.save() # Get the user profile user_profile = UserProfile.objects.get(user=user) user_profile.complete_name = data['first_name'] + ' ' + data['last_name'] if 'notification_url' in data: # Check notification URL format if data['notification_url'] and not is_valid_url(data['notification_url']): raise Exception('Invalid notification URL format') user_profile.current_organization.notification_url = data['notification_url'] user_profile.current_organization.save() if 'provider' in data['roles']: # Append the provider role to the user organization # The user profile is just created so only the private organization exists org = user_profile.organizations[0] org['roles'].append('provider') user_profile.save() user_profile.organizations = [org] if 'tax_address' in data: user_profile.tax_address = { 'street': data['tax_address']['street'], 'postal': data['tax_address']['postal'], 'city': data['tax_address']['city'], 'country': data['tax_address']['country'] } if 'payment_info' in data: if not is_valid_credit_card(data['payment_info']['number']): raise Exception() user_profile.payment_info = { 'type': data['payment_info']['type'], 'number': data['payment_info']['number'], 'expire_month': data['payment_info']['expire_month'], 'expire_year': data['payment_info']['expire_year'], 'cvv2': data['payment_info']['cvv2'] } user_profile.save() except Exception as e: return build_response(request, 400, unicode(e)) return build_response(request, 201, 'Created')
def validate_plugin_info(self, plugin_info): """ Validates the structure of the package.json file of a plugin """ reason = None # Check plugin_info format if not isinstance(plugin_info, dict): reason = 'Plugin info must be a dict instance' # Validate structure if reason is None and "name" not in plugin_info: reason = 'Missing required field: name' # Validate types if reason is None and not isinstance(plugin_info['name'], str) and not isinstance( plugin_info['name'], unicode): reason = 'Plugin name must be an string' if reason is None and not is_valid_id(plugin_info['name']): reason = 'Invalid name format: invalid character' if reason is None and "author" not in plugin_info: reason = 'Missing required field: author' if reason is None and 'formats' not in plugin_info: reason = 'Missing required field: formats' if reason is None and 'module' not in plugin_info: reason = 'Missing required field: module' if reason is None and 'version' not in plugin_info: reason = 'Missing required field: version' if reason is None and not isinstance( plugin_info['author'], str) and not isinstance( plugin_info['author'], unicode): reason = 'Plugin author must be an string' if reason is None and not isinstance(plugin_info['formats'], list): reason = 'Plugin formats must be a list' # Validate formats if reason is None: valid_format, i = self._check_list_field(['FILE', 'URL'], plugin_info['formats']) if not valid_format or (i < 1 and i > 2): reason = 'Format must contain at least one format of: FILE, URL' # Validate overrides if reason is None and 'overrides' in plugin_info and not self._check_list_field( ["NAME", "VERSION", "OPEN"], plugin_info['overrides'])[0]: reason = "Override values should be one of: NAME, VERSION and OPEN" if reason is None and 'media_types' in plugin_info and not isinstance( plugin_info['media_types'], list): reason = 'Plugin media_types must be a list' if reason is None and not isinstance( plugin_info['module'], str) and not isinstance( plugin_info['module'], unicode): reason = 'Plugin module must be an string' if reason is None and not is_valid_version(plugin_info['version']): reason = 'Invalid format in plugin version' if reason is None and 'form' in plugin_info: if not isinstance(plugin_info['form'], dict): reason = 'Invalid format in form field, must be an object' else: reason = self._validate_plugin_form(plugin_info['form']) return reason
def create(self, request): # Only the admin can register new RSS instances if not request.user.is_staff: return build_response(request, 403, 'Forbidden') data = json.loads(request.raw_post_data) if not 'name' in data or not 'host': return build_response(request, 400, 'RSS creation error: Missing a required field') # Check name regex if not is_valid_id(data['name']): return build_response(request, 400, 'RSS creation error: Invalid name format') # Check url regex if not is_valid_url(data['host']): return build_response(request, 400, 'RSS creation error: Invalid URL format') # Check if the information provided is not already registered if len(RSS.objects.filter(name=data['name'])) > 0 or \ len(RSS.objects.filter(host=data['host'])) > 0: return build_response(request, 409, 'RSS creation error: The RSS instance already exists') limits = {} cont = Context.objects.all()[0] # Check request limits if 'limits' in data: try: limits = _check_limits(data['limits']) except Exception as e: return build_response(request, 400, unicode(e)) if not len(limits): # Set default limits limits = { 'currency': cont.allowed_currencies['default'], 'perTransaction': 10000, 'weekly': 100000, 'daily': 10000, 'monthly': 100000 } # Check revenue sharing models sharing_models = [] if 'models' in data: try: sharing_models = _check_revenue_models(data['models']) except Exception as e: return build_response(request, 400, unicode(e)) else: # Set default revenue models sharing_models = [{ 'class': 'single-payment', 'percentage': 10.0 },{ 'class': 'subscription', 'percentage': 20.0 },{ 'class': 'use', 'percentage': 30.0 }] # Build revenue models db_revenue_models = [] for model in sharing_models: db_revenue_models.append(RevenueModel( revenue_class=model['class'], percentage=Decimal(model['percentage']) )) # Create the new entry rss = RSS.objects.create( name=data['name'], host=data['host'], expenditure_limits=limits, revenue_models=db_revenue_models ) exp_manager = ExpenditureManager(rss, request.user.userprofile.access_token) # Create default expenditure limits call_result = _make_rss_request(exp_manager, exp_manager.set_provider_limit, request.user) if call_result[0]: rss.delete() # Return error response return build_response(request, call_result[1], call_result[2]) # Create default revenue sharing models model_manager = ModelManager(rss, request.user.userprofile.access_token) model_created = False for model in sharing_models: def call_model_creation(): model_manager.create_revenue_model(model) call_result = _make_rss_request(model_manager, call_model_creation, request.user) if call_result[0] and not model_created: rss.delete() return build_response(request, call_result[1], call_result[2]) elif not call_result[0]: model_created = True # The request has been success so the used credentials are valid # Store the credentials for future access rss.access_token = request.user.userprofile.access_token rss.refresh_token = request.user.userprofile.refresh_token rss.save() return build_response(request, 201, 'Created')
def register_resource(provider, data, file_=None): # Check if the resource already exists existing = True current_organization = provider.userprofile.current_organization try: Resource.objects.get(name=data['name'], provider=current_organization) except: existing = False if existing: raise ValueError('The resource ' + data['name'] + ' already exists. Please upgrade the resource if you want to provide new content') # Check contents if not 'name' in data or not 'version' in data or\ not 'description' in data or not 'content_type' in data: raise ValueError('Invalid request: Missing required field') # Check version format if not re.match(re.compile(r'^(?:[1-9]\d*\.|0\.)*(?:[1-9]\d*|0)$'), data['version']): raise ValueError('Invalid version format') # Check name format if not is_valid_id(data['name']): raise ValueError('Invalid name format') resource_data = { 'name': data['name'], 'version': data['version'], 'description': data['description'], 'content_type': data['content_type'] } if not file_: if 'content' in data: resource_data['content_path'] = _save_resource_file(current_organization.name, data['name'], data['version'], data['content']) resource_data['link'] = '' elif 'link' in data: # Add the download link # Check link format if not is_valid_url(data['link']): raise ValueError('Invalid resource link format') resource_data['link'] = data['link'] resource_data['content_path'] = '' else: raise ValueError('Invalid request: Missing resource content') else: resource_data['content_path'] = _save_resource_file(current_organization.name, data['name'], data['version'], file_) resource_data['link'] = '' Resource.objects.create( name=resource_data['name'], provider=current_organization, version=resource_data['version'], description=resource_data['description'], download_link=resource_data['link'], resource_path=resource_data['content_path'], content_type=resource_data['content_type'], state='created', open=data.get('open', False) )
def validate_plugin_info(self, plugin_info): """ Validates the structure of the package.json file of a plugin """ reason = None # Check plugin_info format if not isinstance(plugin_info, dict): reason = 'Plugin info must be a dict instance' # Validate structure if reason is None and "name" not in plugin_info: reason = 'Missing required field: name' # Validate types if reason is None and not isinstance(plugin_info['name'], str): reason = 'Plugin name must be an string' if reason is None and not is_valid_id(plugin_info['name']): reason = 'Invalid name format: invalid character' if reason is None and "author" not in plugin_info: reason = 'Missing required field: author' if reason is None and 'formats' not in plugin_info: reason = 'Missing required field: formats' if reason is None and 'module' not in plugin_info: reason = 'Missing required field: module' if reason is None and 'version' not in plugin_info: reason = 'Missing required field: version' if reason is None and not isinstance(plugin_info['author'], str): reason = 'Plugin author must be an string' if reason is None and not isinstance(plugin_info['formats'], list): reason = 'Plugin formats must be a list' # Validate formats if reason is None: valid_format, i = self._check_list_field(['FILE', 'URL'], plugin_info['formats']) if not valid_format or (i < 1 and i > 2): reason = 'Format must contain at least one format of: FILE, URL' # Validate overrides if reason is None and 'overrides' in plugin_info and not self._check_list_field(["NAME", "VERSION", "OPEN"], plugin_info['overrides'])[0]: reason = "Override values should be one of: NAME, VERSION and OPEN" if reason is None and 'media_types' in plugin_info and not isinstance(plugin_info['media_types'], list): reason = 'Plugin media_types must be a list' if reason is None and not isinstance(plugin_info['module'], str): reason = 'Plugin module must be an string' if reason is None and not is_valid_version(plugin_info['version']): reason = 'Invalid format in plugin version' if reason is None and 'pull_accounting' in plugin_info and not isinstance(plugin_info['pull_accounting'], bool): reason = 'Plugin pull_accounting property must be a boolean' if reason is None and 'form' in plugin_info: if not isinstance(plugin_info['form'], dict): reason = 'Invalid format in form field, must be an object' else: reason = self._validate_plugin_form(plugin_info['form']) if reason is None and 'form_order' in plugin_info: if not isinstance(plugin_info['form_order'], list): return 'Invalid format in formOrder' if not 'form' in plugin_info: return 'Form Order cannot be specified without a form' # Check if all the form fields are included matched_keys = [key for key in plugin_info['form'].keys() if key in plugin_info['form_order']] if len(plugin_info['form'].keys()) != len(plugin_info['form_order']) or len(matched_keys) != len(plugin_info['form_order']): reason = 'If form order is provided all form keys need to be provided' return reason