You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by po...@apache.org on 2022/08/02 21:06:40 UTC
[airflow] branch main updated: First/last names can be empty (#25476)
This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 3421ecc21b First/last names can be empty (#25476)
3421ecc21b is described below
commit 3421ecc21bafaf355be5b79ec4ed19768e53275a
Author: Mark Norman Francis <no...@201created.com>
AuthorDate: Tue Aug 2 22:06:33 2022 +0100
First/last names can be empty (#25476)
* First/last names can be empty
The User schema restricts first and last names to not-null, and an
empty string satisfies that requirement. The API insisted names have
at least one character, which caused errors when the database had an
acceptably empty string.
---
airflow/api_connexion/openapi/v1.yaml | 6 +-
airflow/www/static/js/types/api-generated.ts | 4 +-
.../api_connexion/endpoints/test_user_endpoint.py | 100 +++++++++++++++++++--
3 files changed, 96 insertions(+), 14 deletions(-)
diff --git a/airflow/api_connexion/openapi/v1.yaml b/airflow/api_connexion/openapi/v1.yaml
index 3e9222e255..58dad1bc1d 100644
--- a/airflow/api_connexion/openapi/v1.yaml
+++ b/airflow/api_connexion/openapi/v1.yaml
@@ -2134,15 +2134,13 @@ components:
description: |
The user's first name.
- *Changed in version 2.2.0*: A minimum character length requirement ('minLength') is added.
- minLength: 1
+ *Changed in version 2.4.0*: The requirement for this to be non-empty was removed.
last_name:
type: string
description: |
The user's last name.
- *Changed in version 2.2.0*: A minimum character length requirement ('minLength') is added.
- minLength: 1
+ *Changed in version 2.4.0*: The requirement for this to be non-empty was removed.
username:
type: string
description: |
diff --git a/airflow/www/static/js/types/api-generated.ts b/airflow/www/static/js/types/api-generated.ts
index 674e295b76..64c70f633d 100644
--- a/airflow/www/static/js/types/api-generated.ts
+++ b/airflow/www/static/js/types/api-generated.ts
@@ -654,13 +654,13 @@ export interface components {
/**
* @description The user's first name.
*
- * *Changed in version 2.2.0*: A minimum character length requirement ('minLength') is added.
+ * *Changed in version 2.4.0*: The requirement for this to be non-empty was removed.
*/
first_name?: string;
/**
* @description The user's last name.
*
- * *Changed in version 2.2.0*: A minimum character length requirement ('minLength') is added.
+ * *Changed in version 2.4.0*: The requirement for this to be non-empty was removed.
*/
last_name?: string;
/**
diff --git a/tests/api_connexion/endpoints/test_user_endpoint.py b/tests/api_connexion/endpoints/test_user_endpoint.py
index a217dfe76b..b49cb93a1d 100644
--- a/tests/api_connexion/endpoints/test_user_endpoint.py
+++ b/tests/api_connexion/endpoints/test_user_endpoint.py
@@ -106,6 +106,90 @@ class TestGetUser(TestUserEndpoint):
'username': 'TEST_USER1',
}
+ def test_last_names_can_be_empty(self):
+ prince = User(
+ first_name='Prince',
+ last_name='',
+ username='prince',
+ email='prince@example.org',
+ roles=[],
+ created_on=timezone.parse(DEFAULT_TIME),
+ changed_on=timezone.parse(DEFAULT_TIME),
+ )
+ self.session.add_all([prince])
+ self.session.commit()
+ response = self.client.get("/api/v1/users/prince", environ_overrides={'REMOTE_USER': "test"})
+ assert response.status_code == 200
+ assert response.json == {
+ 'active': None,
+ 'changed_on': DEFAULT_TIME,
+ 'created_on': DEFAULT_TIME,
+ 'email': 'prince@example.org',
+ 'fail_login_count': None,
+ 'first_name': 'Prince',
+ 'last_login': None,
+ 'last_name': '',
+ 'login_count': None,
+ 'roles': [],
+ 'username': 'prince',
+ }
+
+ def test_first_names_can_be_empty(self):
+ liberace = User(
+ first_name='',
+ last_name='Liberace',
+ username='liberace',
+ email='liberace@example.org',
+ roles=[],
+ created_on=timezone.parse(DEFAULT_TIME),
+ changed_on=timezone.parse(DEFAULT_TIME),
+ )
+ self.session.add_all([liberace])
+ self.session.commit()
+ response = self.client.get("/api/v1/users/liberace", environ_overrides={'REMOTE_USER': "test"})
+ assert response.status_code == 200
+ assert response.json == {
+ 'active': None,
+ 'changed_on': DEFAULT_TIME,
+ 'created_on': DEFAULT_TIME,
+ 'email': 'liberace@example.org',
+ 'fail_login_count': None,
+ 'first_name': '',
+ 'last_login': None,
+ 'last_name': 'Liberace',
+ 'login_count': None,
+ 'roles': [],
+ 'username': 'liberace',
+ }
+
+ def test_both_first_and_last_names_can_be_empty(self):
+ nameless = User(
+ first_name='',
+ last_name='',
+ username='nameless',
+ email='nameless@example.org',
+ roles=[],
+ created_on=timezone.parse(DEFAULT_TIME),
+ changed_on=timezone.parse(DEFAULT_TIME),
+ )
+ self.session.add_all([nameless])
+ self.session.commit()
+ response = self.client.get("/api/v1/users/nameless", environ_overrides={'REMOTE_USER': "test"})
+ assert response.status_code == 200
+ assert response.json == {
+ 'active': None,
+ 'changed_on': DEFAULT_TIME,
+ 'created_on': DEFAULT_TIME,
+ 'email': 'nameless@example.org',
+ 'fail_login_count': None,
+ 'first_name': '',
+ 'last_login': None,
+ 'last_name': '',
+ 'login_count': None,
+ 'roles': [],
+ 'username': 'nameless',
+ }
+
def test_should_respond_404(self):
response = self.client.get("/api/v1/users/invalid-user", environ_overrides={'REMOTE_USER': "test"})
assert response.status_code == 404
@@ -308,8 +392,8 @@ def autoclean_user_payload(autoclean_username, autoclean_email):
"username": autoclean_username,
"password": "resutsop",
"email": autoclean_email,
- "first_name": "Example",
- "last_name": "User",
+ "first_name": "Tester",
+ "last_name": "",
}
@@ -454,14 +538,14 @@ class TestPatchUser(TestUserEndpoint):
# The first name is changed.
data = response.json
assert data["first_name"] == "Changed"
- assert data["last_name"] == "User"
+ assert data["last_name"] == ""
@pytest.mark.usefixtures("autoclean_admin_user")
- def test_change_with_update_maek(self, autoclean_username, autoclean_user_payload):
+ def test_change_with_update_mask(self, autoclean_username, autoclean_user_payload):
autoclean_user_payload["first_name"] = "Changed"
- autoclean_user_payload["last_name"] = "Overlord"
+ autoclean_user_payload["last_name"] = "McTesterson"
response = self.client.patch(
- f"/api/v1/users/{autoclean_username}?update_mask=first_name",
+ f"/api/v1/users/{autoclean_username}?update_mask=last_name",
json=autoclean_user_payload,
environ_overrides={"REMOTE_USER": "test"},
)
@@ -469,8 +553,8 @@ class TestPatchUser(TestUserEndpoint):
# The first name is changed, but the last name isn't since we masked it.
data = response.json
- assert data["first_name"] == "Changed"
- assert data["last_name"] == "User"
+ assert data["first_name"] == "Tester"
+ assert data["last_name"] == "McTesterson"
@pytest.mark.parametrize(
"payload, error_message",