示例#1
0
    def test_download_csv_file(self):
        # upload the test CSV to get some data in the DB
        self.upload_csv()
        # Add one with null values
        rc_with_nones = RegistrationCenterFactory(name="Center with no center_lat or center_lon",
                                                  center_lat=None,
                                                  center_lon=None)
        self.assertEqual(rc_with_nones.center_lat, None)
        self.assertEqual(rc_with_nones.center_lon, None)

        # download the CSV file
        rsp = self.client.get(self.download_csv_url)
        self.assertEqual(200, rsp.status_code)
        reader = UnicodeReader(StringIO(rsp.content))
        for i, field in enumerate(reader.next()):
            # check the header row
            self.assertEqual(field, CSV_FIELDS[i])
        for row in reader:
            # check each row against the DB values
            self.assertNotIn('None', unicode(row))
            center_id = row[0]
            center = RegistrationCenter.objects.get(center_id=center_id)
            for i, field in enumerate(CSV_FIELDS):
                # center_type is special because it is an integer in the DB, but a string in the CSV
                if field == 'center_type':
                    db_field_as_str = center.get_center_type_display()
                else:
                    db_field_as_str = unicode(getattr(center, field))
                if db_field_as_str == 'None':
                    db_field_as_str = ''
                self.assertEqual(row[i], db_field_as_str)
示例#2
0
    def test_download_csv_file(self):
        # upload the test CSV to get some data in the DB
        self.upload_csv()
        # Add one with null values
        rc_with_nones = RegistrationCenterFactory(
            name="Center with no center_lat or center_lon",
            center_lat=None,
            center_lon=None)
        self.assertEqual(rc_with_nones.center_lat, None)
        self.assertEqual(rc_with_nones.center_lon, None)

        # download the CSV file
        rsp = self.client.get(self.download_csv_url)
        self.assertEqual(200, rsp.status_code)
        reader = UnicodeReader(StringIO(rsp.content))
        for i, field in enumerate(reader.next()):
            # check the header row
            self.assertEqual(field, CSV_FIELDS[i])
        for row in reader:
            # check each row against the DB values
            self.assertNotIn('None', unicode(row))
            center_id = row[0]
            center = RegistrationCenter.objects.get(center_id=center_id)
            for i, field in enumerate(CSV_FIELDS):
                # center_type is special because it is an integer in the DB, but a string in the CSV
                if field == 'center_type':
                    db_field_as_str = center.get_center_type_display()
                else:
                    db_field_as_str = unicode(getattr(center, field))
                if db_field_as_str == 'None':
                    db_field_as_str = ''
                self.assertEqual(row[i], db_field_as_str)
示例#3
0
def update_center_table(_file):
    """
    Import voting centers from a CSV file. It creates or updates.
    Safe to run repeatedly; if a voting center already exists with the
    center ID being imported it will update it if needed.

    Returns a 2-tuple of (message, successful), where message is status information (including
    errors, if any) and successful is a Boolean.

    If any errors are reported, no imports occur.
    """
    errors = []
    reader = UnicodeReader(_file)

    stats = {
        'num_blank': 0,
        'num_created': 0,
        'num_dupes': 0,
        'num_updated': 0,
    }

    line_number = 1
    columns = ", ".join(CSV_FIELDS)
    headers = reader.next()  # gets rid of the header row

    if not len(headers) == len(CSV_FIELDS):
        return PARSING_ERROR.format(line_number=1, columns=columns), False

    for index, header in enumerate(headers):
        if not header == CSV_FIELDS[index]:
            return PARSING_ERROR.format(line_number=1, columns=columns), False

    # If errors happen during the import and we want Django to roll
    # back the transaction, we need to exit the transaction context
    # with an exception (eventually).
    try:
        with transaction.atomic():
            for row in reader:
                line_number += 1
                import_center_csv_row(columns, row, line_number, stats, errors)

            if errors:
                errors.insert(0, force_text(ERRORS_OCCURRED_MESSAGE))
                message = mark_safe('<br><br>'.join(errors))
                logger.debug(errors)
                # trigger rollback:
                raise CenterImportFailedError
            else:
                message = STATUS_MESSAGE.format(blank=stats['num_blank'],
                                                created=stats['num_created'],
                                                dupes=stats['num_dupes'],
                                                updated=stats['num_updated'])
    except CenterImportFailedError:
        # Just to trigger a rollback
        logger.debug("Rolled back all imported centers due to errors.")
    else:
        logger.debug("No errors during import, will commit changes if nothing else goes wrong "
                     "during the request.")

    return message, not bool(errors)
示例#4
0
def validate_uploaded_file(file_path):
    """
    Parse the file to see if it's a valid bulk sms message upload file.

    If not, raises ValidationError

    """
    with open(file_path, "rb") as f:
        reader = UnicodeReader(f)

        line_number = 0
        for row in reader:
            line_number += 1
            if any(row):
                try:
                    line = Line._make(row)
                except TypeError:
                    raise ValidationError(
                        PARSING_ERROR.format(line_number=line_number,
                                             columns=", ".join(FIELDS)))
                if not is_phone_number_valid(line.number):
                    raise ValidationError(
                        INVALID_PHONE_ERROR.format(number=line.number,
                                                   line_number=line_number))
                if not line.message.strip():
                    raise ValidationError(
                        BLANK_MESSAGE_ERROR.format(line_number=line_number))
示例#5
0
    def _request_csv(self, url, **extra):
        """ Like _request() above, but also parse the response body as a CSV
        as created by the voter registration dashboard and log in parsed form.

        This adds the query arg which specifies CSV rendering.
        """
        url += '?format=csv'
        rsp = self._request(url, **extra)
        content = rsp.content[2:]  # skip BOM
        reader = UnicodeReader(StringIO(content),
                               encoding="utf-16-le",
                               delimiter='\t')
        rows = []
        for row in reader:
            rows.append(row)
            logger.info(row)
        return rows
示例#6
0
def read_messages_from_file(file_path):
    """
    Read uploaded bulk SMS file.
    Generate tuples: (phone_number, message, from_shortcode).
    Delete file afterward.
    :param file_path:
    :return:
    """
    # We don't currently enable customization of the from_shortcode via file upload.
    # Just use the default.
    from_shortcode = None
    with open(file_path, "rb") as f:
        reader = UnicodeReader(f)
        for row in reader:
            if any(row):
                line = Line._make(row)
                number = int(line.number)
                yield number, line.message, from_shortcode
    os.remove(file_path)