diff --git a/plane-src/apps/api/plane/app/views/user/base.py b/plane-src/apps/api/plane/app/views/user/base.py index a874e2b..4bb7b23 100644 --- a/plane-src/apps/api/plane/app/views/user/base.py +++ b/plane-src/apps/api/plane/app/views/user/base.py @@ -104,6 +104,13 @@ class UserEndpoint(BaseViewSet): field for field in NODEDC_PROFILE_SYNC_FIELDS if previous_profile.get(field) != getattr(user, field, None) ] + if {"first_name", "last_name"} & set(changed_fields) and "display_name" not in changed_fields: + display_name = " ".join([user.first_name, user.last_name]).strip() + if display_name and user.display_name != display_name: + user.display_name = display_name + user.save(update_fields=["display_name", "updated_at"]) + changed_fields.append("display_name") + if changed_fields: publish_nodedc_user_profile_event_on_commit(user, changed_fields=changed_fields) push_nodedc_user_profile_update_on_commit(user, changed_fields=changed_fields) diff --git a/plane-src/apps/api/plane/authentication/nodedc_profile_sync.py b/plane-src/apps/api/plane/authentication/nodedc_profile_sync.py index 4792cf4..364d9c0 100644 --- a/plane-src/apps/api/plane/authentication/nodedc_profile_sync.py +++ b/plane-src/apps/api/plane/authentication/nodedc_profile_sync.py @@ -61,15 +61,24 @@ def normalize_tasker_avatar_url(value): return avatar_url -def get_user_display_name(user): +def get_user_full_name(user): + return " ".join( + value for value in [getattr(user, "first_name", ""), getattr(user, "last_name", "")] if value + ).strip() + + +def get_user_display_name(user, changed_fields=None): + changed_fields = set(changed_fields or []) + full_name = get_user_full_name(user) display_name = getattr(user, "display_name", "") + + if {"first_name", "last_name"} & changed_fields and "display_name" not in changed_fields and full_name: + return full_name + if display_name: return display_name - name = " ".join( - value for value in [getattr(user, "first_name", ""), getattr(user, "last_name", "")] if value - ).strip() - return name or user.email + return full_name or user.email def get_nodedc_subject(user): @@ -78,17 +87,20 @@ def get_nodedc_subject(user): def build_nodedc_profile_payload(user, changed_fields=None): + changed_fields = sorted(set(changed_fields or [])) + display_name = get_user_display_name(user, changed_fields=changed_fields) + return { "source": "tasker", "planeUserId": str(user.id), "subject": get_nodedc_subject(user), "email": user.email, - "name": get_user_display_name(user), - "displayName": user.display_name or get_user_display_name(user), + "name": display_name, + "displayName": display_name, "firstName": user.first_name, "lastName": user.last_name, "avatarUrl": normalize_tasker_avatar_url(user.avatar_url), - "changedFields": sorted(set(changed_fields or [])), + "changedFields": changed_fields, } diff --git a/plane-src/apps/api/plane/authentication/views/nodedc_workspace_adapter.py b/plane-src/apps/api/plane/authentication/views/nodedc_workspace_adapter.py index e87d7e8..25f6889 100644 --- a/plane-src/apps/api/plane/authentication/views/nodedc_workspace_adapter.py +++ b/plane-src/apps/api/plane/authentication/views/nodedc_workspace_adapter.py @@ -141,6 +141,18 @@ def first_payload_string(payload, *keys): return "" +def split_display_name(value): + if not isinstance(value, str): + return "", "" + + parts = value.strip().split(None, 1) + if not parts: + return "", "" + if len(parts) == 1: + return parts[0], "" + return parts[0], parts[1] + + def normalize_nodedc_avatar_url(value): if not isinstance(value, str): return "" @@ -183,13 +195,26 @@ def resolve_nodedc_launcher_origin(): def sync_user_profile_from_payload(user, payload): updated_fields = [] display_name = first_payload_string(payload, "displayName", "display_name", "name") + first_name = first_payload_string(payload, "firstName", "first_name") + last_name = first_payload_string(payload, "lastName", "last_name") has_avatar = any(key in payload for key in ["avatarUrl", "avatar_url", "avatar"]) avatar_url = normalize_nodedc_avatar_url(first_payload_string(payload, "avatarUrl", "avatar_url", "avatar")) + if display_name and not first_name and not last_name: + first_name, last_name = split_display_name(display_name) + if display_name and user.display_name != display_name: user.display_name = display_name updated_fields.append("display_name") + if first_name and user.first_name != first_name: + user.first_name = first_name + updated_fields.append("first_name") + + if (last_name or first_name) and user.last_name != last_name: + user.last_name = last_name + updated_fields.append("last_name") + if has_avatar and (user.avatar != avatar_url or user.avatar_asset_id is not None): user.avatar = avatar_url user.avatar_asset_id = None