def get_placeholder_form_instance( placeholder_name, dict_to_populate_from, template_type, optional_placeholder=False, allow_international_phone_numbers=False, ): if ( Columns.make_key(placeholder_name) == 'emailaddress' and template_type == 'email' ): field = email_address(label=placeholder_name, gov_user=False) elif ( Columns.make_key(placeholder_name) == 'phonenumber' and template_type == 'sms' ): if allow_international_phone_numbers: field = international_phone_number(label=placeholder_name) else: field = uk_mobile_number(label=placeholder_name) elif optional_placeholder: field = StringField(placeholder_name) else: field = StringField(placeholder_name, validators=[ DataRequired(message='Can’t be empty') ]) PlaceholderForm.placeholder_value = field return PlaceholderForm( placeholder_value=dict_to_populate_from.get(placeholder_name, '') )
def _get_error_for_field(self, key, value): # noqa: C901 if self.is_address_column(key): return if Columns.make_key( key) in self.recipient_column_headers_as_column_keys: if value in [None, ''] or isinstance(value, list): if self.duplicate_recipient_column_headers: return None else: return Cell.missing_field_error try: validate_recipient( value, self.template_type, allow_international_sms=self.allow_international_sms) except (InvalidEmailError, InvalidPhoneError) as error: return str(error) if Columns.make_key(key) not in self.placeholders_as_column_keys: return if value in [None, '']: return Cell.missing_field_error
def validate_address(address_line, column): if Columns.make_key(column) in Columns.from_keys(optional_address_columns).keys(): return address_line if Columns.make_key(column) not in Columns.from_keys(first_column_headings['letter']).keys(): raise TypeError if not address_line or not strip_whitespace(address_line): raise InvalidAddressError('Missing') return address_line
def placeholders(self, value): try: self._placeholders = list(value) + self.recipient_column_headers except TypeError: self._placeholders = self.recipient_column_headers self.placeholders_as_column_keys = [ Columns.make_key(placeholder) for placeholder in self._placeholders ] self.recipient_column_headers_as_column_keys = [ Columns.make_key(placeholder) for placeholder in self.recipient_column_headers ]
def duplicate_recipient_column_headers(self): raw_recipient_column_headers = [ Columns.make_key(column_header) for column_header in self._raw_column_headers if Columns.make_key( column_header) in self.recipient_column_headers_as_column_keys ] return OrderedSet((column_header for column_header in self._raw_column_headers if raw_recipient_column_headers.count( Columns.make_key(column_header)) > 1))
def missing_column_headers(self): required = { Columns.make_key(key): key for key in set([self.recipient_column_header] + self.placeholders) } return set( required[key] for key in set( [Columns.make_key(self.recipient_column_header)] + self.placeholders_as_column_keys ) - set( Columns.make_key(column_header) for column_header in self.column_headers ) )
def rows_with_missing_data(self): return set( row['index'] for row in self.annotated_rows if any( str(key) not in Columns.make_key(self.recipient_column_header) and value.get('error') for key, value in row['columns'].items() ) )
def placeholders(self, value): try: self._placeholders = list(value) self.placeholders_as_column_keys = [ Columns.make_key(placeholder) for placeholder in value ] except TypeError: self._placeholders, self.placeholders_as_column_keys = [], []
def missing_column_headers(self): return set( key for key in self.placeholders if ( Columns.make_key(key) not in self.column_headers_as_column_keys and not self.is_optional_address_column(key) ) )
def values(self, value): if not value: self._values = {} else: placeholders = Columns.from_keys(self.placeholders) self._values = Columns(value).as_dict_with_keys( self.placeholders | set(key for key in value.keys() if Columns.make_key(key) not in placeholders.keys()))
def _get_error_for_field(self, key, value): if key == Columns.make_key(self.recipient_column_header): try: validate_recipient(value, self.template_type) except (InvalidEmailError, InvalidPhoneError) as error: return str(error) if key not in self.placeholders_as_column_keys: return if value in [None, '']: return 'Missing'
def _get_error_for_field(self, key, value): if self.is_optional_address_column(key): return if Columns.make_key( key) in self.recipient_column_headers_as_column_keys: if value in [None, '']: return Cell.missing_field_error try: validate_recipient(value, self.template_type, column=key, international_sms=self.international_sms) except (InvalidEmailError, InvalidPhoneError, InvalidAddressError) as error: return str(error) if Columns.make_key(key) not in self.placeholders_as_column_keys: return if value in [None, '']: return Cell.missing_field_error
def get_rows(self): column_headers = self._raw_column_headers # this is for caching length_of_column_headers = len(column_headers) rows_as_lists_of_columns = self._rows next(rows_as_lists_of_columns, None) # skip the header row for index, row in enumerate(rows_as_lists_of_columns): output_dict = OrderedDict() for column_name, column_value in zip(column_headers, row): column_value = strip_and_remove_obscure_whitespace( column_value) if Columns.make_key( column_name ) in self.recipient_column_headers_as_column_keys: output_dict[column_name] = column_value or None else: insert_or_append_to_dict(output_dict, column_name, column_value or None) length_of_row = len(row) if length_of_column_headers < length_of_row: output_dict[None] = row[length_of_column_headers:] elif length_of_column_headers > length_of_row: for key in column_headers[length_of_row:]: insert_or_append_to_dict(output_dict, key, None) if index < self.max_rows: yield Row( output_dict, index=index, error_fn=self._get_error_for_field, recipient_column_headers=self.recipient_column_headers, placeholders=self.placeholders_as_column_keys, template=self.template, allow_international_letters=self. allow_international_letters, ) else: yield None
def get_annotated_rows(self): if self.too_many_rows: return [] for row_index, row in enumerate(self.rows): if self.template: self.template.values = dict(row.items()) yield dict( columns=Columns({key: { 'data': value, 'error': self._get_error_for_field(key, value), 'ignore': ( key != Columns.make_key(self.recipient_column_header) and key not in self.placeholders_as_column_keys ) } for key, value in row.items()}), index=row_index, message_too_long=bool(self.template and self.template.content_too_long) )
def has_recipient_columns(self): return set( Columns.make_key(recipient_column) for recipient_column in self.recipient_column_headers if not self.is_optional_address_column(recipient_column) ) <= self.column_headers_as_column_keys
def is_optional_address_column(self, key): return (self.template_type == 'letter' and Columns.make_key(key) in Columns.from_keys(optional_address_columns).keys())
def has_recipient_column(self): return Columns.make_key(self.recipient_column_header) in set( Columns.make_key(column_header) for column_header in self.column_headers )
def check_contact_list(service_id, upload_id): form = CsvUploadForm() contents = ContactList.download(service_id, upload_id) first_row = contents.splitlines()[0].strip().rstrip( ',') if contents else '' original_file_name = ContactList.get_metadata(service_id, upload_id).get( 'original_file_name', '') template_type = { 'emailaddress': 'email', 'phonenumber': 'sms', }.get(Columns.make_key(first_row)) recipients = RecipientCSV( contents, template=get_sample_template(template_type or 'sms'), whitelist=itertools.chain.from_iterable( [user.name, user.mobile_number, user.email_address] for user in current_service.active_users) if current_service.trial_mode else None, allow_international_sms=current_service.has_permission( 'international_sms'), max_initial_rows_shown=50, max_errors_shown=50, ) non_empty_column_headers = list(filter(None, recipients.column_headers)) if len(non_empty_column_headers ) > 1 or not template_type or not recipients: return render_template( 'views/uploads/contact-list/too-many-columns.html', recipients=recipients, original_file_name=original_file_name, template_type=template_type, form=form, allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS) if recipients.too_many_rows or not len(recipients): return render_template( 'views/uploads/contact-list/column-errors.html', recipients=recipients, original_file_name=original_file_name, form=form, allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS) row_errors = get_errors_for_csv(recipients, template_type) if row_errors: return render_template( 'views/uploads/contact-list/row-errors.html', recipients=recipients, original_file_name=original_file_name, row_errors=row_errors, form=form, allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS) if recipients.has_errors: return render_template( 'views/uploads/contact-list/column-errors.html', recipients=recipients, original_file_name=original_file_name, form=form, allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS) metadata_kwargs = { 'row_count': len(recipients), 'valid': True, 'original_file_name': original_file_name, 'template_type': template_type } ContactList.set_metadata(service_id, upload_id, **metadata_kwargs) return render_template( 'views/uploads/contact-list/ok.html', recipients=recipients, original_file_name=original_file_name, upload_id=upload_id, )