def move(self): if not self.patch_request.is_component or self.patch_request.parent_type not in self.component_list_types: raise ValidationException('Invalid operation for property type') if self.patch_request.property_value['sourceIndex'] is None \ or self.patch_request.property_value['targetIndex'] is None: raise ValidationException('Invalid move indices') components = self._get_property_value(self.patch_request.parent_name, []) source_index = self.patch_request.property_value.get('sourceIndex', -1) target_index = self.patch_request.property_value.get('targetIndex', -1) if source_index < 0 or target_index < 0 \ or source_index > len(components) or target_index> len(components): raise ValidationException('Index out of range') component = components[source_index] if component is None or component[ 'id'] != self.patch_request.component_id: raise ValidationException('Invalid component id') components.insert(target_index, components.pop(source_index)) self._set_property_value(self.patch_request.parent_name, components) patch_value = { 'sourceIndex': source_index, 'targetIndex': target_index } return self._create_patch_value('move', True, self.patch_request.parent_name, patch_value)
def edit(self): patch_value = None if self.patch_request.is_component: component = None if self.patch_request.parent_type in self.component_selector_types: component = self._get_property_value( self.patch_request.parent_name, {}) elif self.patch_request.parent_type in self.component_list_types: components = self._get_property_value( self.patch_request.parent_name, []) component = next( (c for c in components if c['id'] == self.patch_request.component_id), None) else: raise ValidationException('Invalid component type') if component is None: raise ValidationException('Invalid component') new_value = self._read_property_value( self._request_json.get('propertyDef', {}), self.patch_request.property, self.patch_request.property_value) component['componentData'][ self.patch_request.property.name] = new_value if self.patch_request.parent_type in self.component_list_types: component['displayName'] = self._update_display_name( component, new_value) custom_result = self._get_custom_component_properties() if custom_result is not None: new_value = custom_result patch_value = { 'id': component.get('id'), 'componentData': { self.patch_request.property.name: new_value }, 'displayName': component['displayName'] } else: new_value = self._read_property_value( self._request_json.get('propertyDef', {}), self.patch_request.property, self.patch_request.property_value) patch_value = self._set_property_value( self.patch_request.property.name, new_value) property_name = self.patch_request.parent_name if self.patch_request.is_component else self.patch_request.property.name return self._create_patch_value('edit', self.patch_request.is_component, property_name, patch_value)
def read(self, data): val = super().read(data) if self.required and (val is None or val == ''): raise ValidationException( f'Field {self.property.name} is required', api_field=self.property.name) if self.maxlength > 0 and val is not None and len( val) > self.maxlength: raise ValidationException( f'Field {self.property.name} cannot be more than {self.maxlength} characters long.', api_field=self.property.name) return val
def post(self): prefix = self.get_prefix() file = prefix + request.get_json()['file'] + '/' files = self.get_all() if next((x for x in files if x['name'] == request.get_json()['file']), None) is not None: raise ValidationException('File already exists') content, content_type = self.read_content() s3 = self.get_s3() metadata = { 'author': g.token_data.get('user'), 'containerversionid': str(g.token_data.get('containerVersionId')) } s3.Object(self.get_bucket(), file).put() s3.Object(self.get_bucket(), file + 'draft').put(Body=content, Metadata=metadata, ContentType=content_type) s3.Object(self.get_bucket(), file + 'production').put(Body=b'', Metadata=metadata, ContentType=content_type) return file
def get_property_type(self, type_name): types = { 'asset-select': AssetSelectPropertyType, 'asset-field': AssetFieldPropertyType, 'text': TextPropertyType, 'color': ColorPropertyType, 'image-upload': ImagePropertyType, 'component': ComponentPropertyType, 'components': ComponentsPropertyType, 'checkbox': CheckboxPropertyType, 'toggle': TogglePropertyType, 'translated-text': TranslatedTextProperty, 'dropdown': DropdownPropertyType, 'dropdown-options': DropdownOptionsPropertyType, 'multiselect': MultiselectPropertyType, 'numeric': NumericPropertyType, 'page-link': PageLinkPropertyType, 'code-editor': CodeEditorPropertyType, 'theme-color': ThemeColorPropertyType, 'admin-launcher': AdminLauncherPropertyType, 'html-editor': HtmlEditorPropertyType, 'dynamic-component': DynamicComponentPropertyType, 'dynamic-components': DynamicComponentsPropertyType, 'data-column-components': DataColumnComponentsPropertyType, 'font': FontPropertyType, } prop_type = types.get(type_name) if prop_type is None: raise ValidationException('Unknown type name:' + type_name) return prop_type(self)
def read(self, data): val = super().read(data) if val == "": val = self.property.default try: val = int(val) except Exception as e: raise ValidationException('Invalid Number: ' + str(val)) if (self.too_low(val)) or (self.too_high(val)): raise ValidationException('Invalid Number: ' + str(val) + \ ' - must be in range ' + str(self.min) + ' to ' + str(self.max)) return val
def validate(self, rec): if not db: raise Exception('Unable to validate record without db context') db.session.flush() required = [col.name for col in self._model_class.__table__.columns if not col.nullable if col.name != 'id'] for r in required: if getattr(rec, r) is None or not str(getattr(rec, r)).strip(): raise ValidationException('Field is Required', self.underscore_to_camel(r))
def get_presign_url(self, method, path=''): content_type = request.get_json()['contentType'] prefix = self.get_prefix() file = '' if method == 'POST': file = prefix + request.get_json()['file'] + '/' files = self.get_all() if next( (x for x in files if x['name'] == request.get_json()['file']), None) is not None: raise ValidationException('File already exists') else: file = prefix + path + '/' s3_client = self.get_s3_client() metadata = { 'author': g.token_data.get('user'), 'containerversionid': str(g.token_data.get('containerVersionId')) } metadata_presign = { 'x-amz-meta-author': g.token_data.get('user'), 'x-amz-meta-containerversionid': str(g.token_data.get('containerVersionId')) } #Generate presigned post url good for 3 minutes for upload response = s3_client.generate_presigned_post( Bucket=self.get_bucket(), Key=file + 'draft', Fields=metadata_presign, Conditions=[ ['eq', '$Content-Type', content_type], { 'success_action_status': '201' }, { 'x-amz-meta-author': g.token_data.get('user') }, { 'x-amz-meta-containerversionid': str(g.token_data.get('containerVersionId')) }, ], ExpiresIn=60 * 15) #go ahead and create folder and empty production version if method == 'POST': s3 = self.get_s3() s3.Object(self.get_bucket(), file).put() s3.Object(self.get_bucket(), file + 'production').put(Body=b'', Metadata=metadata, ContentType=content_type) return response
def delete(self): if not self.patch_request.is_component or self.patch_request.parent_type not in self.component_list_types: raise ValidationException('Invalid operation for property type') if self.patch_request.component_id is None: raise ValidationException('Invalid component id') components = self._get_property_value(self.patch_request.parent_name, []) component = next((c for c in components if c['id'] == self.patch_request.component_id), None) if component is None: raise ValidationException('Invalid component id') components.remove(component) self._set_property_value(self.patch_request.parent_name, components) return self._create_patch_value('delete', True, self.patch_request.parent_name, self.patch_request.component_id)
def read(self, data): val = super().read(data) if val is None: val = '#fff' val = val.lower() if not bool(_rgbstring.match(val)): raise ValidationException(400, 'Invalid Color: ' + val) return val
def get_expression(self, column_name, column, op, value): if isinstance(value, str) and value in self.subs: value = self.subs[value] original_value = value if isinstance(value, str) and value.lower() == '_null_': value = None if column is not None: if isinstance(column, JSONB): pass if str(column.type) == 'DATETIME' or str(column.type) == 'DATE': value = parse(value) elif str(column.type) == 'BIGINT' or str(column.type) == 'INT': value = int(str(value)) elif str(column.type) == 'FLOAT': value = float(str(value)) elif str(column.type) == 'BOOLEAN': value = str(value).lower() == 'true' if op != 'eq': raise ValidationException( 'Booleans can only be filtered using an equals operator', api_field=column_name) if op == 'eq': if str(column.type) == 'BIGINT[]': return column.any(value) else: return column == value elif op == 'neq': return column != value elif op == 'gt': return column > value elif op == 'gte': return column >= value elif op == 'lt': return column < value elif op == 'lte': return column <= value elif op == 'sw': return cast(column, String).ilike(original_value + '%') elif op == 'ct': return cast(column, String).ilike('%' + original_value + '%') elif op == 'aeq': return and_(column.op('@>')(value), column.op('<@')(value)) elif op == 'adeq': return and_(column.op('@>')(value), column.op('<@')(value)) elif op == 'act': return column.contains(value) elif op == 'jsonbstrct': # Checks if jsonb array contains a given string return column.op('?')(value) elif op == 'jsonbstrctd': # Checks if jsonb array contains a given integer return column.op('@>')(value)
def add(self): if not self.patch_request.is_component: raise ValidationException('Only components can be added') if not self.patch_request.is_component or self.patch_request.parent_type not in self.component_list_types: raise ValidationException('Invalid operation for property type') components = self._get_property_value(self.patch_request.parent_name, []) new_component = self._parse_component_data() if self.is_component_valid( self.patch_request.component['componentType']): component_def = self.get_component_def( self.patch_request.component['componentType']) new_component['componentTemplate'] = component_def.get( 'template', '') components.append(new_component) return self._create_patch_value('add', self.patch_request.is_component, self.patch_request.parent_name, new_component)
def read(self, data): val = data.get(self.property.name) check_hash = { str(x): x for x in self.property.options } check_hash['None'] = None if val is None: val = self.property.default if str(val) not in check_hash: raise ValidationException('Invalid Value: ' + str(val) + ' - must be in set ' + ','.join(list(self.property.options.keys()))) return val
def read_content(self): data = request.get_json() contents = data.get('contents') if contents is None: raise ValidationException('file must be uploaded as base-64 data', api_field='contents') content_type = 'binary/octet-stream' content = b'' if ',' in contents: content_type = contents.split(',')[0].split(':')[1].split(';')[0] contents = contents.split(',')[1] content = base64.b64decode(contents) return content, content_type
def _parse_component_data(self): if not self.patch_request.is_component: raise ValidationException('Invalid operation for property type') future_prop_data = {} new_component = self.patch_request.property_value component_prop_json = self._request_json.get('componentDef', {}).get('properties', []) for prop in self.patch_request.component.get('properties', []): prop_json = next( (p for p in component_prop_json if p['name'] == prop.name), None) future_prop_data[prop.name] = \ self._read_property_value(prop_json, prop, new_component.get('componentData', {}).get(prop.name, prop.default)) new_component['componentData'] = future_prop_data return self._pack_component(new_component)
def replace(self): if not self.patch_request.is_component or self.patch_request.parent_type not in self.component_selector_types: raise ValidationException('Invalid operation for property type') patch_value = None if self.patch_request.component_type is None: patch_value = self._set_property_value( self.patch_request.parent_name, self._get_none_component_type()) else: new_component = self._parse_component_data() component_type = self.patch_request.component.get('componentType') if component_type is None: component_type = self.patch_request.component.get('type') if self.is_component_valid(component_type): component_def = self.get_component_def(component_type) new_component['componentTemplate'] = component_def.get( 'template', '') patch_value = self._set_property_value( self.patch_request.parent_name, new_component) return self._create_patch_value('replace', True, self.patch_request.parent_name, patch_value)
def read(self, data): val = data.get(self.property.name, []) components = [] for c in val: comp_values = {} component_type = c.get('componentType', '__NOTYPE__') component_data = c.get('componentData', {}) component_id = c.get('id', None) component_json = next( (x for x in self.property.options.get('components', []) if x['type'] == component_type), None) if component_json is None: raise ValidationException('Invalid Dynamic Component Value: ' + component_type) components.append( DynamicComponentPropertyType.get_component_data( component_id, component_type, component_data, component_json)) self.value = components return components
def read(self, data): val = super().read(data) components = [] for c in val: comp_values = {} component_type = c.get('componentType', c.get('type', '__NOTYPE__')) component_data = c.get('componentData', {}) component_json = next( (x for x in self.property.options.get('components', []) if x['type'] == component_type), None) if component_json: from ..components import Components component = Components.DynamicComponent.from_json( component_json) component_data = component.read(component_data) display_name = component.label additional_display = component_data.get('title') if additional_display and isinstance( additional_display, dict) and 'en-us' in additional_display: display_name = display_name + ' - ' + str( additional_display['en-us']) elif additional_display: display_name = display_name + ' - ' + str( additional_display) result = { 'id': c.get('id'), 'componentType': c.get('componentType', c.get('type')), 'componentData': c.get('componentData', {}), 'displayName': display_name, 'versionId': c.get('versionId', component.component_set_version_id), 'componentSetId': c.get('componentSetId', component.component_set_id), 'icon': c.get('icon') } display_name_template = None if component.display_name is not None and '{{' in component.display_name: display_name_template = component.display_name if component.component_type in g.all_components: component_meta = g.all_components.get( component.component_type, {}) # Flag the component as being used so widget proxy can update component set namespace version table component_meta.update({'isUsed': True}) result['componentTemplate'] = component_meta.get( 'template', '') display_name_template = component_meta.get( 'displayNameTemplate') if display_name_template is None and 'displayNameTemplate' in component_json: display_name_template = component_json.get( 'displayNameTemplate') if display_name_template: rtemplate = Environment( loader=BaseLoader).from_string(display_name_template) result['displayName'] = rtemplate.render(**result) components.append(result) else: raise ValidationException('Invalid Value: ' + component_type) self.value = components return components
def default(self): raise ValidationException('Invalid patch operation')
def get_component_def(self, component_type): raise ValidationException('Not implemented')