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*&#58; A minimum character length requirement ('minLength') is added.
-          minLength: 1
+            *Changed in version 2.4.0*&#58; 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*&#58; A minimum character length requirement ('minLength') is added.
-          minLength: 1
+            *Changed in version 2.4.0*&#58; 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*&#58; A minimum character length requirement ('minLength') is added.
+       * *Changed in version 2.4.0*&#58; 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*&#58; A minimum character length requirement ('minLength') is added.
+       * *Changed in version 2.4.0*&#58; 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",