mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-24 13:04:06 +00:00
Safely handle missing fields during import for LocalBaserowUserSource and LocalBaserowPasswordAppAuthProvider
This commit is contained in:
parent
5f8c81271a
commit
7e32a8d2ed
5 changed files with 181 additions and 3 deletions
changelog/entries/unreleased/bug
enterprise/backend
src/baserow_enterprise/integrations/local_baserow
tests/baserow_enterprise_tests/integrations/local_baserow
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"type": "bug",
|
||||||
|
"message": "[Builder] Fixed bug that caused a workspace import to fail when certain fields were missing.",
|
||||||
|
"issue_number": 3375,
|
||||||
|
"bullet_points": [],
|
||||||
|
"created_at": "2025-01-28"
|
||||||
|
}
|
|
@ -187,7 +187,7 @@ class LocalBaserowPasswordAppAuthProviderType(AppAuthProviderType):
|
||||||
and value
|
and value
|
||||||
and "database_fields" in id_mapping
|
and "database_fields" in id_mapping
|
||||||
):
|
):
|
||||||
return id_mapping["database_fields"][value]
|
return id_mapping["database_fields"].get(value)
|
||||||
|
|
||||||
return super().deserialize_property(
|
return super().deserialize_property(
|
||||||
prop_name,
|
prop_name,
|
||||||
|
|
|
@ -416,14 +416,14 @@ class LocalBaserowUserSourceType(UserSourceType):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if value and "database_tables" in id_mapping and prop_name == "table_id":
|
if value and "database_tables" in id_mapping and prop_name == "table_id":
|
||||||
return id_mapping["database_tables"][value]
|
return id_mapping["database_tables"].get(value)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
value
|
value
|
||||||
and "database_fields" in id_mapping
|
and "database_fields" in id_mapping
|
||||||
and prop_name in ("email_field_id", "name_field_id", "role_field_id")
|
and prop_name in ("email_field_id", "name_field_id", "role_field_id")
|
||||||
):
|
):
|
||||||
return id_mapping["database_fields"][value]
|
return id_mapping["database_fields"].get(value)
|
||||||
|
|
||||||
return super().deserialize_property(
|
return super().deserialize_property(
|
||||||
prop_name,
|
prop_name,
|
||||||
|
|
|
@ -395,3 +395,75 @@ def test_import_local_baserow_password_app_auth_provider(data_fixture):
|
||||||
imported_instance.auth_providers.first().specific.password_field_id
|
imported_instance.auth_providers.first().specific.password_field_id
|
||||||
== password_field.id
|
== password_field.id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_import_local_baserow_password_app_auth_provider_without_database(data_fixture):
|
||||||
|
"""
|
||||||
|
Test the import of the LocalBaserowPasswordAppAuthProvider when the
|
||||||
|
password field is missing in the id_mapping.
|
||||||
|
|
||||||
|
The password field might be missing during an import, because the user
|
||||||
|
might have either deleted the password field in the database, or deleted
|
||||||
|
the table entirely.
|
||||||
|
"""
|
||||||
|
|
||||||
|
user = data_fixture.create_user()
|
||||||
|
workspace = data_fixture.create_workspace(user=user)
|
||||||
|
application = data_fixture.create_builder_application(workspace=workspace)
|
||||||
|
database = data_fixture.create_database_application(workspace=workspace)
|
||||||
|
|
||||||
|
integration = data_fixture.create_local_baserow_integration(
|
||||||
|
application=application, user=user
|
||||||
|
)
|
||||||
|
|
||||||
|
table_from_same_workspace1, fields, rows = data_fixture.build_table(
|
||||||
|
user=user,
|
||||||
|
database=database,
|
||||||
|
columns=[
|
||||||
|
("Email", "text"),
|
||||||
|
("Name", "text"),
|
||||||
|
("Password", "password"),
|
||||||
|
],
|
||||||
|
rows=[
|
||||||
|
["test@baserow.io", "Test", "password"],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
email_field, name_field, password_field = fields
|
||||||
|
|
||||||
|
TO_IMPORT = {
|
||||||
|
"email_field_id": 42,
|
||||||
|
"id": 28,
|
||||||
|
"integration_id": 42,
|
||||||
|
"name": "Test name",
|
||||||
|
"name_field_id": 43,
|
||||||
|
"order": "1.00000000000000000000",
|
||||||
|
"table_id": 42,
|
||||||
|
"type": "local_baserow",
|
||||||
|
"auth_providers": [
|
||||||
|
{
|
||||||
|
"id": 42,
|
||||||
|
"type": "local_baserow_password",
|
||||||
|
"domain": None,
|
||||||
|
"enabled": True,
|
||||||
|
"password_field_id": 44,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
id_mapping = defaultdict(MirrorDict)
|
||||||
|
id_mapping["integrations"] = {42: integration.id}
|
||||||
|
id_mapping["database_tables"] = {42: table_from_same_workspace1.id}
|
||||||
|
|
||||||
|
# the password field is intentionally excluded from database_fields
|
||||||
|
id_mapping["database_fields"] = {
|
||||||
|
42: email_field.id,
|
||||||
|
43: name_field.id,
|
||||||
|
}
|
||||||
|
|
||||||
|
imported_instance = UserSourceHandler().import_user_source(
|
||||||
|
application, TO_IMPORT, id_mapping
|
||||||
|
)
|
||||||
|
|
||||||
|
assert imported_instance.auth_providers.first().specific.password_field_id is None
|
||||||
|
|
|
@ -868,6 +868,105 @@ def test_import_local_baserow_user_source(data_fixture):
|
||||||
assert imported_instance.name_field_id == name_field.id
|
assert imported_instance.name_field_id == name_field.id
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"id_mapping_key,missing_field_name",
|
||||||
|
[
|
||||||
|
("database_tables", "table_id"),
|
||||||
|
("database_fields", "email_field_id"),
|
||||||
|
("database_fields", "name_field_id"),
|
||||||
|
("database_fields", "role_field_id"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_import_local_baserow_user_source_with_missing_fields(
|
||||||
|
data_fixture, id_mapping_key, missing_field_name
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Test the import of the LocalBaserowUserSource when one or more fields
|
||||||
|
are missing in the exported workspace's database.
|
||||||
|
|
||||||
|
A field, such as the Role field might have been deleted before the user
|
||||||
|
has exported the workspace. As such, when importing the workspace, the
|
||||||
|
missing field needs to be safely handled.
|
||||||
|
"""
|
||||||
|
|
||||||
|
user = data_fixture.create_user()
|
||||||
|
workspace = data_fixture.create_workspace(user=user)
|
||||||
|
application = data_fixture.create_builder_application(workspace=workspace)
|
||||||
|
database = data_fixture.create_database_application(workspace=workspace)
|
||||||
|
|
||||||
|
integration = data_fixture.create_local_baserow_integration(
|
||||||
|
application=application, user=user
|
||||||
|
)
|
||||||
|
|
||||||
|
table_from_same_workspace1, fields, rows = data_fixture.build_table(
|
||||||
|
user=user,
|
||||||
|
database=database,
|
||||||
|
columns=[
|
||||||
|
("Email", "text"),
|
||||||
|
("Name", "text"),
|
||||||
|
("Role", "text"),
|
||||||
|
],
|
||||||
|
rows=[
|
||||||
|
["test@baserow.io", "Test", "Foo Role"],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
email_field, name_field, role_field = fields
|
||||||
|
|
||||||
|
TO_IMPORT = {
|
||||||
|
"id": 28,
|
||||||
|
"name": "Test name",
|
||||||
|
"order": "1.00000000000000000000",
|
||||||
|
"type": "local_baserow",
|
||||||
|
"integration_id": 42,
|
||||||
|
"table_id": 42,
|
||||||
|
"name_field_id": 43,
|
||||||
|
"email_field_id": 42,
|
||||||
|
"role_field_id": 44,
|
||||||
|
"auth_providers": [
|
||||||
|
{
|
||||||
|
"id": 42,
|
||||||
|
"type": "local_baserow_password",
|
||||||
|
"domain": None,
|
||||||
|
"enabled": True,
|
||||||
|
"password_field_id": None,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
id_mapping = defaultdict(MirrorDict)
|
||||||
|
|
||||||
|
id_mapping_data = {
|
||||||
|
"table_id": (42, table_from_same_workspace1.id),
|
||||||
|
"email_field_id": (42, email_field.id),
|
||||||
|
"name_field_id": (43, name_field.id),
|
||||||
|
"role_field_id": (44, role_field.id),
|
||||||
|
}
|
||||||
|
id_mapping["integrations"] = {42: integration.id}
|
||||||
|
id_mapping["database_tables"] = {42: table_from_same_workspace1.id}
|
||||||
|
id_mapping["database_fields"] = {
|
||||||
|
42: email_field.id,
|
||||||
|
43: name_field.id,
|
||||||
|
44: role_field.id,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remove a specific field to simulate a "missing field"
|
||||||
|
id_mapping[id_mapping_key].pop(id_mapping_data[missing_field_name][0])
|
||||||
|
|
||||||
|
imported_instance = UserSourceHandler().import_user_source(
|
||||||
|
application, TO_IMPORT, id_mapping
|
||||||
|
)
|
||||||
|
|
||||||
|
for property in id_mapping_data:
|
||||||
|
value = getattr(imported_instance, property)
|
||||||
|
if property == missing_field_name:
|
||||||
|
# Ensure that None is returned instead of raising a KeyError
|
||||||
|
assert value is None
|
||||||
|
else:
|
||||||
|
assert value is id_mapping_data[property][1]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_create_local_baserow_user_source_w_auth_providers(api_client, data_fixture):
|
def test_create_local_baserow_user_source_w_auth_providers(api_client, data_fixture):
|
||||||
user, token = data_fixture.create_user_and_token()
|
user, token = data_fixture.create_user_and_token()
|
||||||
|
|
Loading…
Add table
Reference in a new issue