def test_link_row_field_type(data_fixture): user = data_fixture.create_user() database = data_fixture.create_database_application(user=user, name='Placeholder') table = data_fixture.create_database_table(name='Example', database=database) customers_table = data_fixture.create_database_table(name='Customers', database=database) cars_table = data_fixture.create_database_table(name='Cars', database=database) unrelated_table_1 = data_fixture.create_database_table(name='Unrelated') field_handler = FieldHandler() row_handler = RowHandler() # Create a primary field and some example data for the customers table. customers_primary_field = field_handler.create_field(user=user, table=customers_table, type_name='text', name='Name', primary=True) customers_row_1 = row_handler.create_row( user=user, table=customers_table, values={f'field_{customers_primary_field.id}': 'John'}) customers_row_2 = row_handler.create_row( user=user, table=customers_table, values={f'field_{customers_primary_field.id}': 'Jane'}) # Create a primary field and some example data for the cars table. cars_primary_field = field_handler.create_field(user=user, table=cars_table, type_name='text', name='Name', primary=True) cars_row_1 = row_handler.create_row( user=user, table=cars_table, values={f'field_{cars_primary_field.id}': 'BMW'}) cars_row_2 = row_handler.create_row( user=user, table=cars_table, values={f'field_{cars_primary_field.id}': 'Audi'}) with pytest.raises(LinkRowTableNotProvided): field_handler.create_field(user=user, table=table, type_name='link_row', name='Without table') with pytest.raises(LinkRowTableNotInSameDatabase): field_handler.create_field(user=user, table=table, type_name='link_row', name='Unrelated', link_row_table=unrelated_table_1) link_field_1 = field_handler.create_field(user=user, table=table, type_name='link_row', name='Customer', link_row_table=customers_table) link_field_2 = field_handler.create_field(user=user, table=table, type_name='link_row', name='Customer', link_row_table=customers_table) assert link_field_1.link_row_related_field.name == 'Example' assert link_field_2.link_row_related_field.name == 'Example' connection = connections['default'] tables = connection.introspection.table_names() assert (link_field_1.through_table_name == link_field_1.link_row_related_field.through_table_name) assert (link_field_2.through_table_name == link_field_2.link_row_related_field.through_table_name) assert link_field_1.through_table_name in tables assert link_field_2.through_table_name in tables model = table.get_model() table_row = model.objects.create() getattr(table_row, f'field_{link_field_1.id}').add(customers_row_1.id) results = getattr(table_row, f'field_{link_field_1.id}').all() assert len(results) == 1 assert getattr(results[0], f'field_{customers_primary_field.id}') == 'John' getattr(table_row, f'field_{link_field_2.id}').add(customers_row_1.id, customers_row_2.id) results = getattr(table_row, f'field_{link_field_2.id}').all() assert len(results) == 2 assert getattr(results[0], f'field_{customers_primary_field.id}') == 'John' assert getattr(results[1], f'field_{customers_primary_field.id}') == 'Jane' table_row_2 = model.objects.create() getattr(table_row_2, f'field_{link_field_1.id}').add(customers_row_2.id) results = getattr(table_row_2, f'field_{link_field_1.id}').all() assert len(results) == 1 assert getattr(results[0], f'field_{customers_primary_field.id}') == 'Jane' # Going to change only the name of the field. This should not result in any errors # of schema changes. link_field_1 = field_handler.update_field(user, link_field_1, name='Customer 2') with pytest.raises(LinkRowTableNotInSameDatabase): field_handler.update_field(user, link_field_1, link_row_table=unrelated_table_1) model = table.get_model() assert model.objects.all().count() == 2 # Change the table, this should destroy all relations. old_link_field_1_relation_id = link_field_1.link_row_relation_id link_field_1 = field_handler.update_field(user, link_field_1, link_row_table=cars_table) model = table.get_model() table_rows = model.objects.all() table_row = table_rows[0] table_row_2 = table_rows[1] assert link_field_1.link_row_table.id == cars_table.id assert link_field_1.link_row_relation_id == old_link_field_1_relation_id assert getattr(table_row, f'field_{link_field_1.id}').all().count() == 0 assert getattr(table_row, f'field_{link_field_2.id}').all().count() == 2 assert getattr(table_row_2, f'field_{link_field_1.id}').all().count() == 0 assert getattr(table_row_2, f'field_{link_field_2.id}').all().count() == 0 link_field_2 = field_handler.update_field(user, link_field_2, new_type_name='text') model = table.get_model() table_row = model.objects.all().first() assert getattr(table_row, f'field_{link_field_2.id}') is None assert LinkRowField.objects.all().count() == 2 setattr(table_row, f'field_{link_field_2.id}', 'Text value') table_row.save() assert getattr(table_row, f'field_{link_field_2.id}') == 'Text value' # Delete the existing field. Alter that the related field should be deleted and # no table named _relation_ should exist. field_handler.delete_field(user, link_field_1) assert LinkRowField.objects.all().count() == 0 for t in connection.introspection.table_names(): if '_relation_' in t: assert False # Change a the text field back into a link row field. link_field_2 = field_handler.update_field(user, link_field_2, new_type_name='link_row', link_row_table=customers_table) assert link_field_2.link_row_related_field.name == 'Example' assert (link_field_2.through_table_name == link_field_2.link_row_related_field.through_table_name) assert link_field_2.through_table_name in connection.introspection.table_names( ) assert LinkRowField.objects.all().count() == 2 model = table.get_model() table_row = model.objects.all().first() getattr(table_row, f'field_{link_field_2.id}').add(customers_row_1.id, customers_row_2.id) results = getattr(table_row, f'field_{link_field_2.id}').all() assert len(results) == 2 assert getattr(results[0], f'field_{customers_primary_field.id}') == 'John' assert getattr(results[1], f'field_{customers_primary_field.id}') == 'Jane'
def test_date_field_type(data_fixture): user = data_fixture.create_user() table = data_fixture.create_database_table(user=user) field_handler = FieldHandler() row_handler = RowHandler() amsterdam = timezone('Europe/Amsterdam') utc = timezone('utc') date_field_1 = field_handler.create_field(user=user, table=table, type_name='date', name='Date') date_field_2 = field_handler.create_field(user=user, table=table, type_name='date', name='Datetime', date_include_time=True) assert date_field_1.date_include_time == False assert date_field_2.date_include_time == True assert len(DateField.objects.all()) == 2 model = table.get_model(attribute_names=True) row = row_handler.create_row(user=user, table=table, values={}, model=model) assert row.date == None assert row.datetime == None row = row_handler.create_row(user=user, table=table, values={ 'date': '2020-4-1', 'datetime': '2020-4-1 12:30:30' }, model=model) row.refresh_from_db() assert row.date == date(2020, 4, 1) assert row.datetime == datetime(2020, 4, 1, 12, 30, 30, tzinfo=utc) row = row_handler.create_row(user=user, table=table, values={ 'datetime': make_aware( datetime(2020, 4, 1, 12, 30, 30), amsterdam) }, model=model) row.refresh_from_db() assert row.date == None assert row.datetime == datetime(2020, 4, 1, 10, 30, 30, tzinfo=timezone('UTC')) date_field_1 = field_handler.update_field(user=user, field=date_field_1, date_include_time=True) date_field_2 = field_handler.update_field(user=user, field=date_field_2, date_include_time=False) assert date_field_1.date_include_time == True assert date_field_2.date_include_time == False model = table.get_model(attribute_names=True) rows = model.objects.all() assert rows[0].date == None assert rows[0].datetime == None assert rows[1].date == datetime(2020, 4, 1, tzinfo=timezone('UTC')) assert rows[1].datetime == date(2020, 4, 1) assert rows[2].date == None assert rows[2].datetime == date(2020, 4, 1) field_handler.delete_field(user=user, field=date_field_1) field_handler.delete_field(user=user, field=date_field_2) assert len(DateField.objects.all()) == 0
def test_email_field_type(data_fixture): user = data_fixture.create_user() table = data_fixture.create_database_table(user=user) table_2 = data_fixture.create_database_table(user=user, database=table.database) field = data_fixture.create_text_field(table=table, order=1, name='name') field_handler = FieldHandler() row_handler = RowHandler() field_2 = field_handler.create_field(user=user, table=table, type_name='email', name='email') number = field_handler.create_field(user=user, table=table, type_name='number', name='number') assert len(EmailField.objects.all()) == 1 model = table.get_model(attribute_names=True) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={'email': 'invalid_email'}, model=model) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={'email': 'invalid@email'}, model=model) row_0 = row_handler.create_row(user=user, table=table, values={ 'name': '*****@*****.**', 'email': '*****@*****.**', 'number': 5 }, model=model) row_1 = row_handler.create_row(user=user, table=table, values={ 'name': 'someuser', 'email': '*****@*****.**', 'number': 10 }, model=model) row_2 = row_handler.create_row(user=user, table=table, values={ 'name': 'http://www.baserow.io', 'email': '*****@*****.**' }, model=model) row_3 = row_handler.create_row(user=user, table=table, values={ 'name': 'NOT AN EMAIL', 'email': '*****@*****.**' }, model=model) row_4 = row_handler.create_row(user=user, table=table, values={ 'name': '*****@*****.**', 'email': '' }, model=model) row_5 = row_handler.create_row(user=user, table=table, values={ 'email': None, }, model=model) row_6 = row_handler.create_row(user=user, table=table, values={}, model=model) # Convert the text field to a url field so we can check how the conversion of # values went. field_handler.update_field(user=user, field=field, new_type_name='email') field_handler.update_field(user=user, field=number, new_type_name='email') model = table.get_model(attribute_names=True) rows = model.objects.all() assert rows[0].name == '*****@*****.**' assert rows[0].email == '*****@*****.**' assert rows[0].number == '' assert rows[1].name == '' assert rows[1].email == '*****@*****.**' assert rows[1].number == '' assert rows[2].name == '' assert rows[2].email == '*****@*****.**' assert rows[2].number == '' assert rows[3].name == '' assert rows[3].email == '*****@*****.**' assert rows[3].number == '' assert rows[4].name == '*****@*****.**' assert rows[4].email == '' assert rows[4].number == '' assert rows[5].name == '' assert rows[5].email == '' assert rows[5].number == '' assert rows[6].name == '' assert rows[6].email == '' assert rows[6].number == '' field_handler.delete_field(user=user, field=field_2) assert len(EmailField.objects.all()) == 2
def test_single_select_field_type(data_fixture): user = data_fixture.create_user() database = data_fixture.create_database_application(user=user, name='Placeholder') table = data_fixture.create_database_table(name='Example', database=database) field_handler = FieldHandler() field = field_handler.create_field(user=user, table=table, type_name='single_select', name='Single select', select_options=[{ 'value': 'Option 1', 'color': 'blue' }]) assert SingleSelectField.objects.all().first().id == field.id assert SelectOption.objects.all().count() == 1 select_options = field.select_options.all() assert len(select_options) == 1 assert select_options[0].order == 0 assert select_options[0].field_id == field.id assert select_options[0].value == 'Option 1' assert select_options[0].color == 'blue' field = field_handler.update_field(user=user, table=table, field=field, select_options=[ { 'value': 'Option 2 B', 'color': 'red 2' }, { 'id': select_options[0].id, 'value': 'Option 1 B', 'color': 'blue 2' }, ]) assert SelectOption.objects.all().count() == 2 select_options_2 = field.select_options.all() assert len(select_options_2) == 2 assert select_options_2[0].order == 0 assert select_options_2[0].field_id == field.id assert select_options_2[0].value == 'Option 2 B' assert select_options_2[0].color == 'red 2' assert select_options_2[1].id == select_options[0].id assert select_options_2[1].order == 1 assert select_options_2[1].field_id == field.id assert select_options_2[1].value == 'Option 1 B' assert select_options_2[1].color == 'blue 2' field_handler.delete_field(user=user, field=field) assert SelectOption.objects.all().count() == 0 field = field_handler.create_field(user=user, table=table, type_name='single_select', select_options=[]) field_handler.update_field(user=user, field=field, new_type_name='text')
def test_url_field_type(data_fixture): user = data_fixture.create_user() table = data_fixture.create_database_table(user=user) table_2 = data_fixture.create_database_table(user=user, database=table.database) field = data_fixture.create_text_field(table=table, order=1, name='name') field_handler = FieldHandler() row_handler = RowHandler() field_2 = field_handler.create_field(user=user, table=table, type_name='url', name='url') number = field_handler.create_field(user=user, table=table, type_name='number', name='number') assert len(URLField.objects.all()) == 1 model = table.get_model(attribute_names=True) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={'url': 'invalid_url'}, model=model) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={'url': 'httpss'}, model=model) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={'url': 'httpss'}, model=model) row_0 = row_handler.create_row(user=user, table=table, values={ 'name': 'http://test.nl', 'url': 'https://baserow.io', 'number': 5 }, model=model) row_1 = row_handler.create_row(user=user, table=table, values={ 'name': 'http;//', 'url': 'http://localhost', 'number': 10 }, model=model) row_2 = row_handler.create_row(user=user, table=table, values={ 'name': '*****@*****.**', 'url': 'http://www.baserow.io' }, model=model) row_3 = row_handler.create_row( user=user, table=table, values={ 'name': 'NOT A URL', 'url': 'http://www.baserow.io/blog/building-a-database' }, model=model) row_4 = row_handler.create_row( user=user, table=table, values={ 'name': 'ftps://www.complex.website.com?querystring=test&something=else', 'url': '' }, model=model) row_5 = row_handler.create_row(user=user, table=table, values={ 'url': None, }, model=model) row_6 = row_handler.create_row(user=user, table=table, values={}, model=model) # Convert to text field to a url field so we can check how the conversion of values # went. field_handler.update_field(user=user, field=field, new_type_name='url') field_handler.update_field(user=user, field=number, new_type_name='url') model = table.get_model(attribute_names=True) rows = model.objects.all() assert rows[0].name == 'http://test.nl' assert rows[0].url == 'https://baserow.io' assert rows[0].number == '' assert rows[1].name == '' assert rows[1].url == 'http://localhost' assert rows[1].number == '' assert rows[2].name == '' assert rows[2].url == 'http://www.baserow.io' assert rows[2].number == '' assert rows[3].name == '' assert rows[3].url == 'http://www.baserow.io/blog/building-a-database' assert rows[3].number == '' assert (rows[4].name == 'ftps://www.complex.website.com?querystring=test&something=else') assert rows[4].url == '' assert rows[4].number == '' assert rows[5].name == '' assert rows[5].url == '' assert rows[5].number == '' assert rows[6].name == '' assert rows[6].url == '' assert rows[6].number == '' field_handler.delete_field(user=user, field=field_2) assert len(URLField.objects.all()) == 2
def test_file_field_type(data_fixture): user = data_fixture.create_user() table = data_fixture.create_database_table(user=user) user_file_1 = data_fixture.create_user_file() user_file_2 = data_fixture.create_user_file() user_file_3 = data_fixture.create_user_file() field_handler = FieldHandler() row_handler = RowHandler() file = field_handler.create_field(user=user, table=table, type_name='file', name='File') assert FileField.objects.all().count() == 1 model = table.get_model(attribute_names=True) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={ 'file': 'not_a_json' }, model=model) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={ 'file': {} }, model=model) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={ 'file': [{'no_name': 'test'}] }, model=model) with pytest.raises(InvalidUserFileNameError): row_handler.create_row(user=user, table=table, values={ 'file': [{'name': 'wrongfilename.jpg'}] }, model=model) with pytest.raises(UserFileDoesNotExist): row_handler.create_row(user=user, table=table, values={ 'file': [{'name': 'file_name.jpg'}] }, model=model) row = row_handler.create_row(user=user, table=table, values={ 'file': [{'name': user_file_1.name}] }, model=model) assert row.file[0]['visible_name'] == user_file_1.original_name del row.file[0]['visible_name'] assert row.file[0] == user_file_1.serialize() row = row_handler.create_row(user=user, table=table, values={ 'file': [ {'name': user_file_2.name}, {'name': user_file_1.name}, {'name': user_file_1.name} ] }, model=model) assert row.file[0]['visible_name'] == user_file_2.original_name assert row.file[1]['visible_name'] == user_file_1.original_name assert row.file[2]['visible_name'] == user_file_1.original_name del row.file[0]['visible_name'] del row.file[1]['visible_name'] del row.file[2]['visible_name'] assert row.file[0] == user_file_2.serialize() assert row.file[1] == user_file_1.serialize() assert row.file[2] == user_file_1.serialize() row = row_handler.create_row(user=user, table=table, values={ 'file': [ {'name': user_file_1.name}, {'name': user_file_3.name}, {'name': user_file_2.name} ] }, model=model) assert row.file[0]['visible_name'] == user_file_1.original_name assert row.file[1]['visible_name'] == user_file_3.original_name assert row.file[2]['visible_name'] == user_file_2.original_name del row.file[0]['visible_name'] del row.file[1]['visible_name'] del row.file[2]['visible_name'] assert row.file[0] == user_file_1.serialize() assert row.file[1] == user_file_3.serialize() assert row.file[2] == user_file_2.serialize() row = row_handler.update_row(user=user, table=table, row_id=row.id, values={ 'file': [ {'name': user_file_1.name, 'visible_name': 'not_original.jpg'}, ] }, model=model) assert row.file[0]['visible_name'] == 'not_original.jpg' del row.file[0]['visible_name'] assert row.file[0] == user_file_1.serialize() assert model.objects.all().count() == 3 field_handler.delete_field(user=user, field=file) assert FileField.objects.all().count() == 0 model.objects.all().delete() text = field_handler.create_field(user=user, table=table, type_name='text', name='Text') model = table.get_model(attribute_names=True) row = row_handler.create_row(user=user, table=table, values={ 'text': 'Some random text' }, model=model) row_handler.create_row(user=user, table=table, values={ 'text': '["Not compatible"]' }, model=model) row_handler.create_row(user=user, table=table, values={ 'text': json.dumps(user_file_1.serialize()) }, model=model) file = field_handler.update_field(user=user, table=table, field=text, new_type_name='file', name='File') model = table.get_model(attribute_names=True) results = model.objects.all() assert results[0].file == [] assert results[1].file == [] assert results[2].file == [] row_handler.update_row(user=user, table=table, row_id=row.id, values={ 'file': [ {'name': user_file_1.name, 'visible_name': 'not_original.jpg'}, ] }, model=model) field_handler.update_field(user=user, table=table, field=file, new_type_name='text', name='text') model = table.get_model(attribute_names=True) results = model.objects.all() assert results[0].text is None assert results[1].text is None assert results[2].text is None
def test_phone_number_field_type(data_fixture): user = data_fixture.create_user() table = data_fixture.create_database_table(user=user) data_fixture.create_database_table(user=user, database=table.database) field_handler = FieldHandler() row_handler = RowHandler() text_field = field_handler.create_field(user=user, table=table, order=1, type_name='text', name='name') phone_number_field = field_handler.create_field(user=user, table=table, type_name='phone_number', name='phonenumber') email_field = field_handler.create_field(user=user, table=table, type_name='email', name='email') number_field = data_fixture.create_number_field(table=table, order=1, number_negative=True, name="number") assert len(PhoneNumberField.objects.all()) == 1 model = table.get_model(attribute_names=True) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={ 'phonenumber': 'invalid phone number' }, model=model) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={ 'phonenumber': 'Phone: 2312321 2349432 ' }, model=model) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={ 'phonenumber': '1' * (PhoneNumberFieldType.MAX_PHONE_NUMBER_LENGTH+1) }, model=model) max_length_phone_number = '1' * PhoneNumberFieldType.MAX_PHONE_NUMBER_LENGTH row_handler.create_row(user=user, table=table, values={ 'name': '+45(1424) 322314 324234', 'phonenumber': max_length_phone_number, 'number': 1234534532, 'email': '*****@*****.**' }, model=model) row_handler.create_row(user=user, table=table, values={ 'name': 'some text which should be blanked out after conversion', 'phonenumber': '1234567890 NnXx,+._*()#=;/ -', 'number': 0 }, model=model) row_handler.create_row(user=user, table=table, values={ 'name': max_length_phone_number, 'phonenumber': '', 'number': -10230450, }, model=model) row_handler.create_row(user=user, table=table, values={ 'phonenumber': None, 'name': '1' * (PhoneNumberFieldType.MAX_PHONE_NUMBER_LENGTH+1) }, model=model) row_handler.create_row(user=user, table=table, values={}, model=model) # No actual database type change occurs here as a phone number field is also a text # field. Instead the after_update hook is being used to clear out invalid # phone numbers. field_handler.update_field(user=user, field=text_field, new_type_name='phone_number') field_handler.update_field(user=user, field=number_field, new_type_name='phone_number') field_handler.update_field(user=user, field=email_field, new_type_name='phone_number') model = table.get_model(attribute_names=True) rows = model.objects.all() assert rows[0].name == '+45(1424) 322314 324234' assert rows[0].phonenumber == max_length_phone_number assert rows[0].number == '1234534532' assert rows[0].email == '' assert rows[1].name == '' assert rows[1].phonenumber == '1234567890 NnXx,+._*()#=;/ -' assert rows[1].number == '0' assert rows[2].name == max_length_phone_number assert rows[2].phonenumber == '' assert rows[2].number == '-10230450' assert rows[3].name == '' assert rows[3].phonenumber == '' assert rows[3].number == '' field_handler.delete_field(user=user, field=phone_number_field) assert len(PhoneNumberField.objects.all()) == 3
def test_date_field_type(data_fixture): user = data_fixture.create_user() table = data_fixture.create_database_table(user=user) field_handler = FieldHandler() row_handler = RowHandler() amsterdam = timezone("Europe/Amsterdam") utc = timezone("utc") date_field_1 = field_handler.create_field(user=user, table=table, type_name="date", name="Date") date_field_2 = field_handler.create_field( user=user, table=table, type_name="date", name="Datetime", date_include_time=True, ) assert date_field_1.date_include_time is False assert date_field_2.date_include_time is True assert len(DateField.objects.all()) == 2 model = table.get_model(attribute_names=True) row = row_handler.create_row(user=user, table=table, values={}, model=model) assert row.date is None assert row.datetime is None row = row_handler.create_row( user=user, table=table, values={ "date": "2020-4-1", "datetime": "2020-4-1 12:30:30" }, model=model, ) row.refresh_from_db() assert row.date == date(2020, 4, 1) assert row.datetime == datetime(2020, 4, 1, 12, 30, 30, tzinfo=utc) row = row_handler.create_row( user=user, table=table, values={ "datetime": make_aware(datetime(2020, 4, 1, 12, 30, 30), amsterdam) }, model=model, ) row.refresh_from_db() assert row.date is None assert row.datetime == datetime(2020, 4, 1, 10, 30, 30, tzinfo=timezone("UTC")) date_field_1 = field_handler.update_field(user=user, field=date_field_1, date_include_time=True) date_field_2 = field_handler.update_field(user=user, field=date_field_2, date_include_time=False) assert date_field_1.date_include_time is True assert date_field_2.date_include_time is False model = table.get_model(attribute_names=True) rows = model.objects.all() assert rows[0].date is None assert rows[0].datetime is None assert rows[1].date == datetime(2020, 4, 1, tzinfo=timezone("UTC")) assert rows[1].datetime == date(2020, 4, 1) assert rows[2].date is None assert rows[2].datetime == date(2020, 4, 1) field_handler.delete_field(user=user, field=date_field_1) field_handler.delete_field(user=user, field=date_field_2) assert len(DateField.objects.all()) == 0
def test_link_row_field_type_rows(data_fixture): user = data_fixture.create_user() database = data_fixture.create_database_application(user=user, name='Placeholder') example_table = data_fixture.create_database_table(name='Example', database=database) customers_table = data_fixture.create_database_table(name='Customers', database=database) users_table = data_fixture.create_database_table(name='Users', database=database) field_handler = FieldHandler() row_handler = RowHandler() link_row_field = field_handler.create_field(user=user, table=example_table, type_name='link_row', link_row_table=customers_table) customers_row_1 = row_handler.create_row(user=user, table=customers_table) customers_row_2 = row_handler.create_row(user=user, table=customers_table) customers_row_3 = row_handler.create_row(user=user, table=customers_table) row = row_handler.create_row(user=user, table=example_table, values={ f'field_{link_row_field.id}': [customers_row_1.id, customers_row_2.id], }) row_2 = row_handler.create_row(user=user, table=example_table, values={ f'field_{link_row_field.id}': [customers_row_1.id], }) example_table.name = 'Example2' example_table.save() customers_table.name = 'Customers2' customers_table.save() row_1_all = getattr(row, f'field_{link_row_field.id}').all() row_2_all = getattr(row_2, f'field_{link_row_field.id}').all() row_1_ids = [i.id for i in row_1_all] row_2_ids = [i.id for i in row_2_all] assert row_1_all.count() == 2 assert row_2_all.count() == 1 assert customers_row_1.id in row_1_ids assert customers_row_2.id in row_1_ids assert customers_row_1.id in row_2_ids row = row_handler.update_row( user=user, table=example_table, row_id=row.id, values={f'field_{link_row_field.id}': [customers_row_3.id]}) row_2 = row_handler.update_row( user=user, table=example_table, row_id=row_2.id, values={ f'field_{link_row_field.id}': [customers_row_2.id, customers_row_1.id] }) row_1_all = getattr(row, f'field_{link_row_field.id}').all() row_2_all = getattr(row_2, f'field_{link_row_field.id}').all() row_1_ids = [i.id for i in row_1_all] row_2_ids = [i.id for i in row_2_all] assert row_1_all.count() == 1 assert row_2_all.count() == 2 assert customers_row_3.id in row_1_ids assert customers_row_1.id in row_2_ids assert customers_row_2.id in row_2_ids # Check if the relations are there via the customers table. customers_table.refresh_from_db() customers_model = customers_table.get_model() related_field = link_row_field.link_row_related_field customer_rows = customers_model.objects.all() assert customer_rows.count() == 3 customers_row_1 = customer_rows[0] customers_row_2 = customer_rows[1] customers_row_3 = customer_rows[2] customer_row_1_all = getattr(customers_row_1, f'field_{related_field.id}').all() customer_row_2_all = getattr(customers_row_2, f'field_{related_field.id}').all() customer_row_3_all = getattr(customers_row_3, f'field_{related_field.id}').all() assert customer_row_1_all.count() == 1 assert customer_row_2_all.count() == 1 assert customer_row_3_all.count() == 1 customers_row_1_ids = [i.id for i in customer_row_1_all] customers_row_2_ids = [i.id for i in customer_row_2_all] customers_row_3_ids = [i.id for i in customer_row_3_all] assert row_2.id in customers_row_1_ids assert row_2.id in customers_row_2_ids assert row.id in customers_row_3_ids # When changing the link row table table all the existing relations should be # deleted. link_row_field = field_handler.update_field(user=user, field=link_row_field, type_name='link_row', link_row_table=users_table) example_table.refresh_from_db() model = example_table.get_model() rows = model.objects.all() row = rows[0] row_2 = rows[1] assert getattr(row, f'field_{link_row_field.id}').all().count() == 0 assert getattr(row_2, f'field_{link_row_field.id}').all().count() == 0 # Just check if the field can be deleted can be deleted. field_handler.delete_field(user=user, field=link_row_field) assert Field.objects.all().count() == 0
def test_single_select_field_type(data_fixture): user = data_fixture.create_user() database = data_fixture.create_database_application(user=user, name="Placeholder") table = data_fixture.create_database_table(name="Example", database=database) field_handler = FieldHandler() field = field_handler.create_field( user=user, table=table, type_name="single_select", name="Single select", select_options=[{ "value": "Option 1", "color": "blue" }], ) assert SingleSelectField.objects.all().first().id == field.id assert SelectOption.objects.all().count() == 1 select_options = field.select_options.all() assert len(select_options) == 1 assert select_options[0].order == 0 assert select_options[0].field_id == field.id assert select_options[0].value == "Option 1" assert select_options[0].color == "blue" field = field_handler.update_field( user=user, table=table, field=field, select_options=[ { "value": "Option 2 B", "color": "red 2" }, { "id": select_options[0].id, "value": "Option 1 B", "color": "blue 2" }, ], ) assert SelectOption.objects.all().count() == 2 select_options_2 = field.select_options.all() assert len(select_options_2) == 2 assert select_options_2[0].order == 0 assert select_options_2[0].field_id == field.id assert select_options_2[0].value == "Option 2 B" assert select_options_2[0].color == "red 2" assert select_options_2[1].id == select_options[0].id assert select_options_2[1].order == 1 assert select_options_2[1].field_id == field.id assert select_options_2[1].value == "Option 1 B" assert select_options_2[1].color == "blue 2" field_handler.delete_field(user=user, field=field) assert SelectOption.objects.all().count() == 0 field = field_handler.create_field(user=user, table=table, type_name="single_select", select_options=[]) field_handler.update_field(user=user, field=field, new_type_name="text")
def test_url_field_type(data_fixture): user = data_fixture.create_user() table = data_fixture.create_database_table(user=user) data_fixture.create_database_table(user=user, database=table.database) field = data_fixture.create_text_field(table=table, order=1, name="name") field_handler = FieldHandler() row_handler = RowHandler() field_2 = field_handler.create_field(user=user, table=table, type_name="url", name="url") number = field_handler.create_field(user=user, table=table, type_name="number", name="number") assert len(URLField.objects.all()) == 1 model = table.get_model(attribute_names=True) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={"url": "invalid_url"}, model=model) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={"url": "httpss"}, model=model) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={"url": "httpss"}, model=model) very_long_url = "https://baserow.io/with-a-very-long-url-that-exceeds-the-old-254-" "char-limit/with-a-very-long-url-that-exceeds-the-old-254-char-limit/with-a-very-" "long-url-that-exceeds-the-old-254-char-limit/with-a-very-long-url-that-exceeds" "-the-old-254-char/with-a-very-long-url-that-exceeds-the-old-254-char/" row_handler.create_row( user=user, table=table, values={ "name": "http://test.nl", "url": very_long_url, "number": 5 }, model=model, ) row_handler.create_row( user=user, table=table, values={ "name": "http;//", "url": "http://localhost", "number": 10 }, model=model, ) row_handler.create_row( user=user, table=table, values={ "name": "*****@*****.**", "url": "http://www.baserow.io" }, model=model, ) row_handler.create_row( user=user, table=table, values={ "name": "NOT A URL", "url": "http://www.baserow.io/blog/building-a-database", }, model=model, ) row_handler.create_row( user=user, table=table, values={ "name": "ftps://www.complex.website.com?querystring=test&something=else", "url": "", }, model=model, ) row_handler.create_row( user=user, table=table, values={ "url": None, }, model=model, ) row_handler.create_row(user=user, table=table, values={}, model=model) # Convert to text field to a url field so we can check how the conversion of values # went. field_handler.update_field(user=user, field=field, new_type_name="url") field_handler.update_field(user=user, field=number, new_type_name="url") model = table.get_model(attribute_names=True) rows = model.objects.all() assert rows[0].name == "http://test.nl" assert rows[0].url == very_long_url assert rows[0].number == "" assert rows[1].name == "" assert rows[1].url == "http://localhost" assert rows[1].number == "" assert rows[2].name == "" assert rows[2].url == "http://www.baserow.io" assert rows[2].number == "" assert rows[3].name == "" assert rows[3].url == "http://www.baserow.io/blog/building-a-database" assert rows[3].number == "" assert (rows[4].name == "ftps://www.complex.website.com?querystring=test&something=else") assert rows[4].url == "" assert rows[4].number == "" assert rows[5].name == "" assert rows[5].url == "" assert rows[5].number == "" assert rows[6].name == "" assert rows[6].url == "" assert rows[6].number == "" field_handler.delete_field(user=user, field=field_2) assert len(URLField.objects.all()) == 2
def test_phone_number_field_type(data_fixture): user = data_fixture.create_user() table = data_fixture.create_database_table(user=user) data_fixture.create_database_table(user=user, database=table.database) field_handler = FieldHandler() row_handler = RowHandler() text_field = field_handler.create_field(user=user, table=table, order=1, type_name="text", name="name") phone_number_field = field_handler.create_field(user=user, table=table, type_name="phone_number", name="phonenumber") email_field = field_handler.create_field(user=user, table=table, type_name="email", name="email") number_field = data_fixture.create_number_field(table=table, order=1, number_negative=True, name="number") assert len(PhoneNumberField.objects.all()) == 1 model = table.get_model(attribute_names=True) with pytest.raises(ValidationError): row_handler.create_row( user=user, table=table, values={"phonenumber": "invalid phone number"}, model=model, ) with pytest.raises(ValidationError): row_handler.create_row( user=user, table=table, values={"phonenumber": "Phone: 2312321 2349432 "}, model=model, ) with pytest.raises(ValidationError): row_handler.create_row( user=user, table=table, values={ "phonenumber": "1" * (PhoneNumberFieldType.MAX_PHONE_NUMBER_LENGTH + 1) }, model=model, ) max_length_phone_number = "1" * PhoneNumberFieldType.MAX_PHONE_NUMBER_LENGTH row_handler.create_row( user=user, table=table, values={ "name": "+45(1424) 322314 324234", "phonenumber": max_length_phone_number, "number": 1234534532, "email": "*****@*****.**", }, model=model, ) row_handler.create_row( user=user, table=table, values={ "name": "some text which should be blanked out after conversion", "phonenumber": "1234567890 NnXx,+._*()#=;/ -", "number": 0, }, model=model, ) row_handler.create_row( user=user, table=table, values={ "name": max_length_phone_number, "phonenumber": "", "number": -10230450, }, model=model, ) row_handler.create_row( user=user, table=table, values={ "phonenumber": None, "name": "1" * (PhoneNumberFieldType.MAX_PHONE_NUMBER_LENGTH + 1), }, model=model, ) row_handler.create_row(user=user, table=table, values={}, model=model) # No actual database type change occurs here as a phone number field is also a text # field. Instead the after_update hook is being used to clear out invalid # phone numbers. field_handler.update_field(user=user, field=text_field, new_type_name="phone_number") field_handler.update_field(user=user, field=number_field, new_type_name="phone_number") field_handler.update_field(user=user, field=email_field, new_type_name="phone_number") model = table.get_model(attribute_names=True) rows = model.objects.all() assert rows[0].name == "+45(1424) 322314 324234" assert rows[0].phonenumber == max_length_phone_number assert rows[0].number == "1234534532" assert rows[0].email == "" assert rows[1].name == "" assert rows[1].phonenumber == "1234567890 NnXx,+._*()#=;/ -" assert rows[1].number == "0" assert rows[2].name == max_length_phone_number assert rows[2].phonenumber == "" assert rows[2].number == "-10230450" assert rows[3].name == "" assert rows[3].phonenumber == "" assert rows[3].number == "" field_handler.delete_field(user=user, field=phone_number_field) assert len(PhoneNumberField.objects.all()) == 3
def test_email_field_type(data_fixture): user = data_fixture.create_user() table = data_fixture.create_database_table(user=user) data_fixture.create_database_table(user=user, database=table.database) field = data_fixture.create_text_field(table=table, order=1, name="name") field_handler = FieldHandler() row_handler = RowHandler() field_2 = field_handler.create_field(user=user, table=table, type_name="email", name="email") number = field_handler.create_field(user=user, table=table, type_name="number", name="number") assert len(EmailField.objects.all()) == 1 model = table.get_model(attribute_names=True) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={"email": "invalid_email"}, model=model) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={"email": "invalid@email"}, model=model) row_handler.create_row( user=user, table=table, values={ "name": "*****@*****.**", "email": "*****@*****.**", "number": 5, }, model=model, ) row_handler.create_row( user=user, table=table, values={ "name": "someuser", "email": "*****@*****.**", "number": 10 }, model=model, ) row_handler.create_row( user=user, table=table, values={ "name": "http://www.baserow.io", "email": "*****@*****.**" }, model=model, ) row_handler.create_row( user=user, table=table, values={ "name": "NOT AN EMAIL", "email": "*****@*****.**" }, model=model, ) row_handler.create_row( user=user, table=table, values={ "name": "*****@*****.**", "email": "" }, model=model, ) row_handler.create_row( user=user, table=table, values={ "email": None, }, model=model, ) row_handler.create_row(user=user, table=table, values={}, model=model) # Convert the text field to a url field so we can check how the conversion of # values went. field_handler.update_field(user=user, field=field, new_type_name="email") field_handler.update_field(user=user, field=number, new_type_name="email") model = table.get_model(attribute_names=True) rows = model.objects.all() assert rows[0].name == "*****@*****.**" assert rows[0].email == "*****@*****.**" assert rows[0].number == "" assert rows[1].name == "" assert rows[1].email == "*****@*****.**" assert rows[1].number == "" assert rows[2].name == "" assert rows[2].email == "*****@*****.**" assert rows[2].number == "" assert rows[3].name == "" assert rows[3].email == "*****@*****.**" assert rows[3].number == "" assert rows[4].name == "*****@*****.**" assert rows[4].email == "" assert rows[4].number == "" assert rows[5].name == "" assert rows[5].email == "" assert rows[5].number == "" assert rows[6].name == "" assert rows[6].email == "" assert rows[6].number == "" field_handler.delete_field(user=user, field=field_2) assert len(EmailField.objects.all()) == 2
def test_file_field_type(data_fixture, user_tables_in_separate_db): user = data_fixture.create_user() table = data_fixture.create_database_table(user=user) user_file_1 = data_fixture.create_user_file() user_file_2 = data_fixture.create_user_file() user_file_3 = data_fixture.create_user_file() field_handler = FieldHandler() row_handler = RowHandler() file = field_handler.create_field(user=user, table=table, type_name="file", name="File") assert FileField.objects.all().count() == 1 model = table.get_model(attribute_names=True) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={"file": "not_a_json"}, model=model) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={"file": {}}, model=model) with pytest.raises(ValidationError): row_handler.create_row(user=user, table=table, values={"file": [{ "no_name": "test" }]}, model=model) with pytest.raises(InvalidUserFileNameError): row_handler.create_row( user=user, table=table, values={"file": [{ "name": "wrongfilename.jpg" }]}, model=model, ) with pytest.raises(UserFileDoesNotExist): row_handler.create_row( user=user, table=table, values={"file": [{ "name": "file_name.jpg" }]}, model=model, ) row = row_handler.create_row( user=user, table=table, values={"file": [{ "name": user_file_1.name }]}, model=model, ) assert row.file[0]["visible_name"] == user_file_1.original_name del row.file[0]["visible_name"] assert row.file[0] == user_file_1.serialize() row = row_handler.create_row( user=user, table=table, values={ "file": [ { "name": user_file_2.name }, { "name": user_file_1.name }, { "name": user_file_1.name }, ] }, model=model, ) assert row.file[0]["visible_name"] == user_file_2.original_name assert row.file[1]["visible_name"] == user_file_1.original_name assert row.file[2]["visible_name"] == user_file_1.original_name del row.file[0]["visible_name"] del row.file[1]["visible_name"] del row.file[2]["visible_name"] assert row.file[0] == user_file_2.serialize() assert row.file[1] == user_file_1.serialize() assert row.file[2] == user_file_1.serialize() row = row_handler.create_row( user=user, table=table, values={ "file": [ { "name": user_file_1.name }, { "name": user_file_3.name }, { "name": user_file_2.name }, ] }, model=model, ) assert row.file[0]["visible_name"] == user_file_1.original_name assert row.file[1]["visible_name"] == user_file_3.original_name assert row.file[2]["visible_name"] == user_file_2.original_name del row.file[0]["visible_name"] del row.file[1]["visible_name"] del row.file[2]["visible_name"] assert row.file[0] == user_file_1.serialize() assert row.file[1] == user_file_3.serialize() assert row.file[2] == user_file_2.serialize() row = row_handler.update_row( user=user, table=table, row_id=row.id, values={ "file": [ { "name": user_file_1.name, "visible_name": "not_original.jpg" }, ] }, model=model, ) assert row.file[0]["visible_name"] == "not_original.jpg" del row.file[0]["visible_name"] assert row.file[0] == user_file_1.serialize() assert model.objects.all().count() == 3 field_handler.delete_field(user=user, field=file) assert FileField.objects.all().count() == 0 model.objects.all().delete() text = field_handler.create_field(user=user, table=table, type_name="text", name="Text") model = table.get_model(attribute_names=True) row = row_handler.create_row(user=user, table=table, values={"text": "Some random text"}, model=model) row_handler.create_row(user=user, table=table, values={"text": '["Not compatible"]'}, model=model) row_handler.create_row( user=user, table=table, values={"text": json.dumps(user_file_1.serialize())}, model=model, ) file = field_handler.update_field(user=user, table=table, field=text, new_type_name="file", name="File") model = table.get_model(attribute_names=True) results = model.objects.all() assert results[0].file == [] assert results[1].file == [] assert results[2].file == [] row_handler.update_row( user=user, table=table, row_id=row.id, values={ "file": [ { "name": user_file_1.name, "visible_name": "not_original.jpg" }, ] }, model=model, ) field_handler.update_field(user=user, table=table, field=file, new_type_name="text", name="text") model = table.get_model(attribute_names=True) results = model.objects.all() assert results[0].text is None assert results[1].text is None assert results[2].text is None