import base64 import hmac import json import os import time from datetime import datetime, timedelta, timezone from hashlib import sha256 import boto3 import pandas as pd import requests S3_BUCKET = "pingcap-plg" API_KEY = os.environ["API_KEY"] SECRET = os.environ.get("SECRET") if os.environ.get("SECRET") else "" BOT_WEBHOOK = os.environ["BOT_WEBHOOK"] TEXT = { "POC": { "title": "New requesting PoC users:", "text_tail": "requested a PoC application.", }, "Billed": { "title": "New billing capable users:", "text_tail": "binded a credit card.", }, "BusinessMail": { "title": "New heavily-used users with business email:", "text_tail": "became a new heavily-used user with business email.", }, "PersonalMail": { "title": "New heavily-used users with personal email:", "text_tail": "became a new heavily-used user with personal email.", }, } REPORT_SUFFIX = { "China Outbound": "co", "NA": "na", "Japan": "jp", "EMEA": "emea", "APAC": "apac", } MSG_COLOR = { "China Outbound": "green", "NA": "blue", "Japan": "yellow", "EMEA": "orange", "APAC": "purple", } def set_enter_date(df_in, _class, begin, end): s3 = boto3.client("s3") table_list = {} df = df_in.copy() df.loc[:, "Enter date"] = end for i, row in df.iterrows(): enter_date = begin while enter_date < end: if table_list.get(f"{_class}-{enter_date}") is None: try: table_list[f"{_class}-{enter_date}"] = pd.read_csv( s3.get_object( Bucket=S3_BUCKET, Key=f"data/classes/{_class}-{enter_date}.csv", )["Body"], low_memory=False, ) except Exception as e: print(f"file: {_class}-{enter_date}.csv has error: {e}") table_list[f"{_class}-{enter_date}"] = pd.DataFrame([], columns=["Tenant ID"]) if row["Tenant ID"] in table_list.get(f"{_class}-{enter_date}")["Tenant ID"].values: # row['Enter date'] = enter_date df.loc[i, "Enter date"] = enter_date break enter_date += timedelta(days=1) return df def get_classes(s3, _date): class_1_1 = pd.read_csv( s3.get_object(Bucket=S3_BUCKET, Key=f"data/classes/class-1-1-{_date}.csv")["Body"], low_memory=False, keep_default_na=False, ) class_1_2 = pd.read_csv( s3.get_object(Bucket=S3_BUCKET, Key=f"data/classes/class-1-2-{_date}.csv")["Body"], low_memory=False, keep_default_na=False, ) class_1_3 = pd.read_csv( s3.get_object(Bucket=S3_BUCKET, Key=f"data/classes/class-1-3-{_date}.csv")["Body"], low_memory=False, keep_default_na=False, ) # class_2 = pd.read_csv( # s3.get_object(Bucket=S3_BUCKET, Key=f"data/classes/class-2-{_date}.csv")[ # "Body" # ], # low_memory=False, # keep_default_na=False, # ) # class_3 = pd.read_csv( # s3.get_object(Bucket=S3_BUCKET, Key=f"data/classes/class-3-{_date}.csv")[ # "Body" # ], # low_memory=False, # keep_default_na=False, # ) # class_other = pd.read_csv( # s3.get_object(Bucket=S3_BUCKET, Key=f"data/classes/class-4-{_date}.csv")[ # "Body" # ], # low_memory=False, # keep_default_na=False, # ) return { "class_1_1": class_1_1, "class_1_2": class_1_2, "class_1_3": class_1_3, # "class_2": class_2, # "class_3": class_3, # "class_4": class_other, } def get_clinic_info(tenant): url = f"https://clinic.pingcap.com/clinic/api/v1/orgs/external/{str(tenant)}" headers = {"Authorization": f"Bearer {API_KEY}"} try: with requests.get(url, headers=headers) as resp: if not resp.ok: print( f"Error get clinic orgid of tenant: {tenant} with status code: {resp.status_code} and reason: {resp.reason}" ) return {"tenant_name": None, "clinic_url": None} res = resp.json() if resp.status_code == 200: clinic_org_id = res["id"] tenant_name = res["name"].split("/")[0] return { "tenant_name": tenant_name, "clinic_url": f"https://clinic.pingcap.com/portal/#/orgs/{clinic_org_id}/clusters", } else: print(f"status code: {resp.status_code} and reason: {resp.reason}") return {"tenant_name": None, "clinic_url": None} except: raise def send_lark_msg(_date, content, area=None): timestamp = str(round(time.time())) key = f"{timestamp}\n{SECRET}".encode("utf-8") msg = "".encode("utf-8") hmac_code = hmac.new(key, msg, digestmod=sha256).digest() sign = base64.b64encode(hmac_code).decode("utf-8") # full_report = f'> [Here](http://172.16.5.134/sales_report_{REPORT_SUFFIX[area]}.html) is a full-report for {area}. \n\n' if area is None: title = "Full Report of TiDB Cloud Product Qualified Leads" else: title = f"{_date} [{area}] TiDB Cloud Product Qualified Leads Daily Report" payload = { # "timestamp": timestamp, # "sign": sign, "msg_type": "interactive", "card": { "config": {"wide_screen_mode": True}, "header": { "title": {"tag": "plain_text", "content": title}, "template": MSG_COLOR[area] if area is not None else "grey", }, "elements": [{"tag": "markdown", "content": content}], # + full_report }, } headers = {"Content-Type": "application/json"} response = requests.request("POST", BOT_WEBHOOK, headers=headers, data=json.dumps(payload)) return response def generate_content(area_users): content = "" null_group = 0 for typ, users in area_users.items(): if len(users) > 0: content += f"**{TEXT[typ]['title']}**\n\n" for user in users: content += f"[{user.get('country')}] Tenant [{user['clinic_info'].get('tenant_name')}]({user['clinic_info'].get('clinic_url')}) (id: [**{user.get('tenant')}**], email: [**{user.get('email')}**]) {TEXT[typ]['text_tail']}\n\n" content += "--------------\n\n" else: null_group += 1 if null_group == len(area_users): content = "There are no new users that need special attention today." return content def lambda_handler(event, context=None): _date = datetime.now().date() if event.get("kwargs") is not None: if event["kwargs"].get("timestamp") is not None: _date = datetime.fromtimestamp(event["kwargs"]["timestamp"], tz=timezone.utc).date() s3 = boto3.client("s3") begin = datetime(2022, 7, 1, tzinfo=timezone.utc) tables = get_classes( s3, _date - timedelta(days=1) ) # get the latest all classes regardless of area for k, v in tables.items(): tables[k] = set_enter_date(v, k.replace("_", "-"), begin.date(), _date) # add enter date tables[k].sort_values(["Event Types"], ascending=False, ignore_index=True) tables[k] = tables[k][ tables[k]["Enter date"] == _date - timedelta(days=1) ] # filter out the users who enter the class on the day tables[k].drop( [ "Owner", "Signup Time", "DBaaS Trial (day)", "Event Types", "Cluster Create", "Clusters Trial (day)", "Enter date", ], inplace=True, axis=1, ) areas = ["China Outbound", "NA", "Japan", "EMEA", "APAC"] users = {} for area in areas: users[area] = { "POC": [], "Billed": [], "BusinessMail": [], "PersonalMail": [], } for _, row in tables["class_1_2"].iterrows(): users[row["Region"]]["PersonalMail"].append( { "tenant": row["Tenant ID"], "email": row["Email"], "country": row["Country"], "clinic_info": get_clinic_info(row["Tenant ID"]), } ) for _, row in tables["class_1_3"].iterrows(): users["China Outbound"]["PersonalMail"].append( { "tenant": row["Tenant ID"], "email": row["Email"], "country": row["Country"], "clinic_info": get_clinic_info(row["Tenant ID"]), } ) for _, row in tables["class_1_1"].iterrows(): if row["PoC Form Submission"] == "Y": users[row["Region"]]["POC"].append( { "tenant": row["Tenant ID"], "email": row["Email"], "country": row["Country"], "clinic_info": get_clinic_info(row["Tenant ID"]), } ) if row["Has Bind Card"] == "Y": users[row["Region"]]["Billed"].append( { "tenant": row["Tenant ID"], "email": row["Email"], "country": row["Country"], "region": row["Region"], "clinic_info": get_clinic_info(row["Tenant ID"]), } ) if row["PoC Form Submission"] == "N" and row["Has Bind Card"] == "N": users[row["Region"]]["BusinessMail"].append( { "tenant": row["Tenant ID"], "email": row["Email"], "country": row["Country"], "clinic_info": get_clinic_info(row["Tenant ID"]), } ) for area, area_users in users.items(): content = generate_content(area_users) res = send_lark_msg(_date, content, area) full_report = "[Here](http://172.16.5.134/sales_report_class1.html) is a full report. \n\n" res = send_lark_msg(_date, full_report) print(res)