import threading import logging import requests import hmac import hashlib import json from django.contrib.auth import get_user_model from django.db.models.signals import post_save from django.dispatch import receiver from django.conf import settings from pingcap_sso.models import SSOUserWebhook from pingcap_sso.tasks.user import ( sync_user_to_discourse, send_welcome_email_to_newbie, send_welcome_asktug_message_to_newbie ) logger = logging.getLogger(__name__) @receiver(post_save, sender=get_user_model()) def _sync_user_data_to_third_party(sender, instance, created, **kwargs): user = instance if settings.DISOCURSE_ENABLE_SSO_SYNC: sync_user_to_discourse.delay( user.openid, user.username, user.email or user.fake_email, user.name, user.bio ) if created: return event_body = { "openid": user.openid, "username": user.username, "avatar_url": user.avatar_url, "email": user.email or user.signup_email, "email_verified": user.email_verified, "phone": user.phone, "name": user.name, "address": user.address, "bio": user.bio, "company_name": user.company_name, "date_of_birth": user.date_of_birth.strftime('%Y-%m-%d') if user.date_of_birth else None, "job_title_code": user.job_title_code, "job_title_text": user.job_title_text, "is_active": user.is_active, } from oauth2_provider.models import AccessToken for webhook in SSOUserWebhook.objects.filter(active=True): if webhook.oauth_application_id: # Sync user data to oauth2 application only when user grants it if not AccessToken.objects.filter(user=user, application_id=webhook.oauth_application_id).exists(): continue t = threading.Thread(target=_async_trigger_webhook, args=(webhook.url, webhook.secret, event_body)) t.start() def _async_trigger_webhook(url, secret, event_body): signature = hmac.new( bytes(secret, 'utf-8'), msg=bytes(json.dumps(event_body), 'utf-8'), digestmod=hashlib.sha256 ).hexdigest() headers = { "X-Event-Type": "userinfo-changed", "X-Event-Signature": "sha256={}".format(signature) } try: resp = requests.post(url, headers=headers, json=event_body, timeout=10) if resp.status_code != 200: logger.error('trigger sso user webhook failed, url: {url}, event_body: {event_body}, status_code: {status_code}, resp_body: {resp_body}'.format( url=url, event_body=event_body, status_code=resp.status_code, resp_body=resp.content )) except Exception as e: logger.error(e) @receiver(post_save, sender=get_user_model()) def _welcome_newbie(sender, instance, created, **kwargs): if created and not (settings.DEBUG or settings.STAGING): send_welcome_email_to_newbie.apply_async((instance.id, ), countdown=60) # wait 180 sec, system should sync userinfo to asktug in 180 sec send_welcome_asktug_message_to_newbie.apply_async((instance.id, ), countdown=180)