from io import BytesIO from datetime import datetime, timezone from copy import deepcopy import requests from requests.auth import HTTPBasicAuth from django.conf import settings from django.utils.text import slugify from labs.models import ( CertificateRecipient, CertificateType, CertificateIssuance, CertLMSLearner, ) from labs.certificate.file import deprecated_upload_certificate_file_to_aliyun_oss EXAMS = { "Practitioner": { "exam_id_list": ["288", "286", "302"], "name": "TiDB Practitioner", }, "PCTA_v6": { "exam_id_list": ["189", "237", "266", "196", "271", "280", "307"], "name": "TiDB Associate v6", }, "PCTP_v6": { "exam_id_list": ["220", "253", "301", "270", "295", "268", "319"], "name": "TiDB Professional Database Administrator v6", }, "PCSD_v6": { "exam_id_list": ["251", "252", "267", "318"], "name": "TiDB SQL Developer", }, "PCTM_v6": {"exam_id_list": [], "name": "TiDB Master Database Administrator v6"}, } TLMS_COURSE_EXAMP_MAP = {} for cert_short_name, cert_metadata in EXAMS.items(): for e_id in cert_metadata["exam_id_list"]: TLMS_COURSE_EXAMP_MAP[e_id] = { "cert_short_name": cert_short_name, "cert_name": cert_metadata["name"], } def get_tlms_user_info(tlms_user_id: str) -> dict: url = f"https://edu.pingcap.com/api/v1/users/id:{tlms_user_id}" response = requests.get(url, auth=HTTPBasicAuth(settings.TLMS_API_KEY, "")) response.raise_for_status() return response.json() def sync_tlms_certificates_for_user(tlms_user_info: dict): tlms_user_id = tlms_user_info["id"] tlms_certifications: list = tlms_user_info["certifications"] external_user_info = deepcopy(tlms_user_info) for key in [ "login_key", "courses", "branches", "groups", "certifications", "badges", ]: del external_user_info[key] try: deprecated_learner = CertLMSLearner.objects.get(user_id=tlms_user_id) user_gid = deprecated_learner.user_gid except CertLMSLearner.DoesNotExist: user_gid = None try: cert_recipient = CertificateRecipient.objects.get( external_user_info__id=tlms_user_id ) except CertificateRecipient.DoesNotExist: cert_recipient = CertificateRecipient.objects.create( first_name=tlms_user_info["first_name"], last_name=tlms_user_info["last_name"], email=tlms_user_info["email"], email_verified=True, country=tlms_user_info["custom_field_1"], company_name=tlms_user_info["custom_field_2"], external_user_info=external_user_info, deprecated_gid=user_gid, ) for certification in tlms_certifications: course_id = certification["course_id"] cert_number = certification["unique_id"] issued_date = certification["issued_date"] issued_date_timestamp = certification["issued_date_timestamp"] issued_at = datetime.strptime(issued_date, "%d/%m/%Y").replace(tzinfo=timezone.utc) tlms_cert_file_public_url = certification["public_url"] if course_id not in TLMS_COURSE_EXAMP_MAP: continue cert_info = TLMS_COURSE_EXAMP_MAP[course_id] cert_name = cert_info["cert_name"] cert_short_name = cert_info["cert_short_name"] cert_type, created = CertificateType.objects.get_or_create( name=cert_name, short_name=cert_short_name, defaults={ "issuer_name": "PingCAP", "issuer_website": "https://www.pingcap.com/education/", }, ) issuance, created = CertificateIssuance.objects.get_or_create( recipient=cert_recipient, cert_type=cert_type, cert_number=cert_number, defaults={ "cert_snapshot": { "first_name": cert_recipient.first_name, "last_name": cert_recipient.last_name, "cert_name": cert_name, "cert_short_name": cert_short_name, "issued_date": issued_date, "issued_date_timestamp": issued_date_timestamp, "tlms_cert_public_url": tlms_cert_file_public_url, }, "issued_at": issued_at, "tlms_course_id": course_id, }, ) if created: response = requests.get(tlms_cert_file_public_url) response.raise_for_status() pdf_file = BytesIO(response.content) if pdf_file.getbuffer().nbytes < 1024 * 100: raise Exception( f"PDF file is too small: {pdf_file.getbuffer().nbytes} bytes, " "this usally means we did not get correct PDF file from TLMS" ) pdf_file_path = ( f"certificates/{slugify(f'{cert_short_name}_{cert_number}')}.pdf" ) issuance.file_storage_provider = "aliyun" issuance.file_bucket = settings.ALIYUN_OSS_BUCKET issuance.file_object_key = pdf_file_path issuance.file_content_type = "application/pdf" deprecated_upload_certificate_file_to_aliyun_oss(pdf_file_path, pdf_file) issuance.save()