ФУНКЦИИ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: синхронизация профиля Tasker
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
import logging
|
||||
import os
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import requests
|
||||
from django.db import transaction
|
||||
|
||||
from plane.authentication.views.nodedc_logout import get_nodedc_internal_token
|
||||
from plane.db.models import ExternalIdentityLink, User
|
||||
|
||||
|
||||
logger = logging.getLogger("plane")
|
||||
OIDC_PROVIDER = "authentik"
|
||||
|
||||
|
||||
def get_nodedc_profile_sync_url():
|
||||
launcher_base_url = (
|
||||
os.environ.get("PLANE_NODEDC_LAUNCHER_URL", "").strip()
|
||||
or os.environ.get("PLANE_NODEDC_LAUNCHER_PUBLIC_URL", "").strip()
|
||||
or "http://launcher.local.nodedc"
|
||||
).rstrip("/")
|
||||
return (
|
||||
os.environ.get("PLANE_NODEDC_PROFILE_SYNC_URL", "").strip()
|
||||
or f"{launcher_base_url}/api/internal/tasker/profile-sync"
|
||||
)
|
||||
|
||||
|
||||
def get_tasker_public_origin():
|
||||
explicit_origin = os.environ.get("PLANE_NODEDC_TASK_PUBLIC_URL", "").strip()
|
||||
if explicit_origin:
|
||||
return explicit_origin.rstrip("/")
|
||||
|
||||
configured_url = os.environ.get("WEB_URL", "").strip()
|
||||
if configured_url:
|
||||
parsed_url = urlparse(configured_url)
|
||||
if parsed_url.scheme and parsed_url.netloc:
|
||||
return f"{parsed_url.scheme}://{parsed_url.netloc}"
|
||||
|
||||
task_domain = os.environ.get("TASK_DOMAIN", "").strip()
|
||||
if task_domain:
|
||||
return f"http://{task_domain}"
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
def normalize_tasker_avatar_url(value):
|
||||
if not isinstance(value, str):
|
||||
return None
|
||||
|
||||
avatar_url = value.strip()
|
||||
if not avatar_url:
|
||||
return None
|
||||
|
||||
if avatar_url.startswith(("http://", "https://", "data:")):
|
||||
return avatar_url
|
||||
|
||||
if avatar_url.startswith("/"):
|
||||
tasker_origin = get_tasker_public_origin()
|
||||
return f"{tasker_origin}{avatar_url}" if tasker_origin else avatar_url
|
||||
|
||||
return avatar_url
|
||||
|
||||
|
||||
def get_user_display_name(user):
|
||||
display_name = getattr(user, "display_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
|
||||
|
||||
|
||||
def get_nodedc_subject(user):
|
||||
link = ExternalIdentityLink.objects.filter(provider=OIDC_PROVIDER, user=user, status="active").first()
|
||||
return link.subject if link else None
|
||||
|
||||
|
||||
def build_nodedc_profile_payload(user, changed_fields=None):
|
||||
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),
|
||||
"firstName": user.first_name,
|
||||
"lastName": user.last_name,
|
||||
"avatarUrl": normalize_tasker_avatar_url(user.avatar_url),
|
||||
"changedFields": sorted(set(changed_fields or [])),
|
||||
}
|
||||
|
||||
|
||||
def push_nodedc_user_profile_update(user, changed_fields=None):
|
||||
request_url = get_nodedc_profile_sync_url()
|
||||
token = get_nodedc_internal_token()
|
||||
|
||||
if not request_url or not token:
|
||||
logger.warning("NODE.DC profile sync is not configured")
|
||||
return None
|
||||
|
||||
response = requests.post(
|
||||
request_url,
|
||||
json=build_nodedc_profile_payload(user, changed_fields=changed_fields),
|
||||
headers={
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Accept": "application/json",
|
||||
},
|
||||
timeout=float(os.environ.get("PLANE_NODEDC_PROFILE_SYNC_TIMEOUT_SECONDS", "3") or "3"),
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
|
||||
def push_nodedc_user_profile_update_on_commit(user, changed_fields=None):
|
||||
user_id = user.id
|
||||
changed_fields = sorted(set(changed_fields or []))
|
||||
|
||||
def _push():
|
||||
fresh_user = User.objects.filter(id=user_id, is_bot=False).first()
|
||||
if fresh_user is None:
|
||||
return
|
||||
|
||||
try:
|
||||
push_nodedc_user_profile_update(fresh_user, changed_fields=changed_fields)
|
||||
except Exception:
|
||||
logger.exception("Failed to push NODE.DC profile update to Launcher")
|
||||
|
||||
transaction.on_commit(_push)
|
||||
Reference in New Issue
Block a user