11import os
2+ import json
23import hmac
34import hashlib
45import requests
56from msal import ConfidentialClientApplication
7+ from datetime import datetime
68
79# --- Determine mode ---
810TEST_MODE = os .getenv ("TEST_MODE" , "true" ).lower () == "true"
911
1012# Only import Flask if not in TEST_MODE
1113if not TEST_MODE :
12- from flask import Flask , request , jsonify
14+ from flask import Flask , request
1315 app = Flask (__name__ )
1416
1517# --- Microsoft Graph Email Sending Function ---
@@ -22,7 +24,7 @@ def send_email_via_graph(subject, body):
2224
2325 if not all ([TENANT_ID , CLIENT_ID , CLIENT_SECRET , FROM_EMAIL , TO_EMAIL ]):
2426 print ("❌ Missing required environment variables" )
25- return False
27+ return
2628
2729 try :
2830 app_msal = ConfidentialClientApplication (
@@ -34,7 +36,7 @@ def send_email_via_graph(subject, body):
3436 access_token = token .get ("access_token" )
3537 if not access_token :
3638 print (f"❌ Failed to get access token: { token } " )
37- return False
39+ return
3840
3941 email_msg = {
4042 "message" : {
@@ -52,14 +54,22 @@ def send_email_via_graph(subject, body):
5254
5355 if response .status_code == 202 :
5456 print (f"✅ Email sent to { TO_EMAIL } " )
55- return True
5657 else :
5758 print (f"❌ Failed to send email: { response .status_code } { response .text } " )
58- return False
5959
6060 except Exception as e :
6161 print (f"❌ Exception occurred while sending email: { e } " )
62- return False
62+
63+ # --- Format GitHub timestamp ---
64+ def format_timestamp (ts ):
65+ """Convert GitHub timestamp to 'YYYY-MM-DD HH:MM:SS' format."""
66+ if not ts :
67+ return None
68+ try :
69+ dt = datetime .strptime (ts , "%Y-%m-%dT%H:%M:%SZ" )
70+ return dt .strftime ("%Y-%m-%d %H:%M:%S" )
71+ except Exception :
72+ return ts # fallback
6373
6474# --- Verify GitHub webhook signature ---
6575def verify_github_signature (payload_body , signature , secret ):
@@ -74,7 +84,7 @@ def verify_github_signature(payload_body, signature, secret):
7484 expected_signature = "sha256=" + mac .hexdigest ()
7585 return hmac .compare_digest (expected_signature , signature )
7686
77- # --- GitHub Webhook Handler ---
87+ # --- GitHub Webhook + Health Handlers ---
7888if not TEST_MODE :
7989 @app .route ("/webhook" , methods = ["POST" ])
8090 def github_webhook ():
@@ -101,24 +111,35 @@ def github_webhook():
101111
102112 event = request .headers .get ("X-GitHub-Event" , "" )
103113
104- # Handle repository create/delete events
105114 if event == "repository" and data .get ("action" ) in ["created" , "deleted" ]:
106115 repo = data .get ("repository" , {})
107- owner = repo .get ("owner" , {})
108116 action = data ["action" ]
109117
110- subject = f"[GitHub Alert] Repository { action } : { repo .get ('full_name' , 'unknown' )} "
111-
112- body = (
113- f"A repository was { action } in your GitHub organization.\n \n "
114- f"📌 Repository Name: { repo .get ('full_name' )} \n "
115- f"🔒 Visibility: { 'Private' if repo .get ('private' ) else 'Public' } \n "
116- f"👤 Owner: { owner .get ('login' )} \n "
117- f"🌍 URL: { repo .get ('html_url' , 'N/A' )} \n "
118- )
118+ repo_name = repo .get ("name" )
119+ full_name = repo .get ("full_name" )
120+ org = repo .get ("owner" , {}).get ("login" )
121+ owner_id = repo .get ("owner" , {}).get ("id" )
122+ default_branch = repo .get ("default_branch" )
123+ created_at = format_timestamp (repo .get ("created_at" ))
124+ updated_at = format_timestamp (repo .get ("updated_at" ))
125+ html_url = repo .get ("html_url" )
126+
127+ subject = f"[GitHub Alert] Repository { action } : { full_name } "
128+ body = f"""
129+ A repository was { action } in your GitHub organization.
130+
131+ Repository: { repo_name }
132+ Full name: { full_name }
133+ Organization: { org }
134+ Owner ID: { owner_id }
135+ Default branch: { default_branch }
136+ Created at: { created_at }
137+ Last updated: { updated_at }
138+ URL: { html_url }
139+ """
119140
120141 print (f"📩 Sending email alert: { subject } " )
121- send_email_via_graph (subject , body )
142+ send_email_via_graph (subject , body . strip () )
122143 else :
123144 print (f"ℹ️ Ignored event: { event } , action: { data .get ('action' )} " )
124145
@@ -127,17 +148,16 @@ def github_webhook():
127148 # Health check endpoint
128149 @app .route ("/health" , methods = ["GET" ])
129150 def health_check ():
130- return jsonify ( {"status" : "running" }) , 200
151+ return {"status" : "running" }, 200
131152
132153# --- Main Entry Point ---
133154if __name__ == "__main__" :
134155 if TEST_MODE :
135156 print ("🔹 TEST_MODE: sending test email" )
136157 send_email_via_graph (
137158 "[Test] Graph Email" ,
138- "This is a test email sent via Microsoft Graph with application permissions. "
159+ "The information of Quantori's GitHub repositories has been updated "
139160 )
140161 else :
141162 print ("✅ Flask is up and listening on /webhook and /health" )
142- port = int (os .getenv ("PORT" , 8000 ))
143- app .run (host = "0.0.0.0" , port = port )
163+ app .run (host = "0.0.0.0" , port = int (os .getenv ("PORT" , 8000 )))
0 commit comments