import os import streamlit as st import requests import msal import secrets from urllib.parse import urlencode from datetime import datetime, timedelta # Configuration APPLICATION_ID = os.getenv('APPLICATION_ID_KEY') CLIENT_SECRET = os.getenv('CLIENT_SECRET_KEY') AUTHORITY = 'https://login.microsoftonline.com/common' REDIRECT_URI = 'https://huggingface.co/spaces/awacke1/MSGraphAPI' SCOPES = ['User.Read', 'Calendars.ReadWrite', 'Mail.ReadWrite', 'Files.ReadWrite.All'] # MSAL setup def get_msal_app(): return msal.ConfidentialClientApplication( client_id=APPLICATION_ID, client_credential=CLIENT_SECRET, authority=AUTHORITY ) # Authentication functions def generate_auth_url(): msal_app = get_msal_app() state = secrets.token_urlsafe(32) auth_url = msal_app.get_authorization_request_url( scopes=SCOPES, redirect_uri=REDIRECT_URI, state=state ) new_query_params = st.query_params.to_dict() new_query_params['auth_state'] = state return f"{auth_url}&{urlencode(new_query_params)}" def get_token_from_code(code): msal_app = get_msal_app() result = msal_app.acquire_token_by_authorization_code( code=code, scopes=SCOPES, redirect_uri=REDIRECT_URI ) if 'access_token' in result: return result else: raise Exception(f"Error acquiring token: {result.get('error_description')}") # API call function def make_api_call(endpoint, token, method='GET', data=None): headers = {'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'} url = f'https://graph.microsoft.com/v1.0/{endpoint}' if method == 'GET': response = requests.get(url, headers=headers) elif method == 'POST': response = requests.post(url, headers=headers, json=data) else: raise ValueError(f"Unsupported method: {method}") if response.status_code in [200, 201]: return response.json() else: st.error(f"API call failed: {response.status_code} - {response.text}") return None # Product integration functions def handle_outlook_integration(token): st.subheader("📧 Outlook Integration") emails = make_api_call('me/messages?$top=5', token) if emails: for email in emails['value']: st.write(f"Subject: {email['subject']}") st.write(f"From: {email['from']['emailAddress']['name']}") st.write("---") def handle_onenote_integration(token): st.subheader("📒 OneNote Integration") notebooks = make_api_call('me/onenote/notebooks', token) if notebooks: for notebook in notebooks['value']: st.write(f"Notebook: {notebook['displayName']}") def handle_calendar_integration(token): st.subheader("📅 Calendar Integration") events = make_api_call('me/events?$top=5', token) if events: for event in events['value']: st.write(f"Event: {event['subject']}") st.write(f"Start: {event['start']['dateTime']}") st.write("---") def handle_onedrive_integration(token): st.subheader("🗂️ OneDrive Integration") files = make_api_call('me/drive/root/children', token) if files: for file in files['value']: st.write(f"File: {file['name']}") st.write(f"Type: {file['file']['mimeType'] if 'file' in file else 'Folder'}") st.write("---") # Main application def main(): st.title("🦄 MS Graph API with AI & Cloud Integration for M365") # Debug information st.sidebar.write("Debug Info:") st.sidebar.write(f"Query Params: {st.query_params.to_dict()}") if 'code' in st.query_params and 'state' in st.query_params: received_state = st.query_params['state'] expected_state = st.query_params.get('auth_state') if received_state != expected_state: st.error(f"Invalid state parameter. Expected {expected_state}, got {received_state}") st.error("Please try logging in again.") st.query_params.clear() st.rerun() try: token = get_token_from_code(st.query_params['code']) st.session_state['token'] = token st.query_params.clear() st.success("Successfully authenticated!") st.rerun() except Exception as e: st.error(f"Authentication failed: {str(e)}") st.query_params.clear() st.rerun() if 'token' not in st.session_state: auth_url = generate_auth_url() st.write("Please log in to continue:") st.markdown(f"[Login with Microsoft]({auth_url})") return # User is authenticated, show the main app token = st.session_state['token']['access_token'] st.sidebar.success("Authenticated successfully!") # Display user info user_info = make_api_call('me', token) if user_info: st.sidebar.write(f"Welcome, {user_info.get('displayName', 'User')}!") # App navigation st.sidebar.title("Navigation") app_mode = st.sidebar.selectbox("Choose the app mode", ["Dashboard", "Product Integration", "Event Management"]) if app_mode == "Dashboard": st.header("📊 Dashboard") # Add dashboard widgets here elif app_mode == "Product Integration": st.header("🧩 Product Integration") products = { "📧 Outlook": handle_outlook_integration, "📒 OneNote": handle_onenote_integration, "📅 Calendar": handle_calendar_integration, "🗂️ OneDrive": handle_onedrive_integration } for product, handler in products.items(): if st.checkbox(f"Enable {product}"): handler(token) elif app_mode == "Event Management": st.header("📅 Event Management") event_action = st.radio("Choose an action", ["View Upcoming Events", "Add New Event"]) if event_action == "View Upcoming Events": events = make_api_call('me/events?$top=10&$orderby=start/dateTime', token) if events: for event in events['value']: st.write(f"Event: {event['subject']}") st.write(f"Start: {event['start']['dateTime']}") st.write("---") elif event_action == "Add New Event": subject = st.text_input("Event Subject") start_date = st.date_input("Start Date") start_time = st.time_input("Start Time") duration = st.number_input("Duration (hours)", min_value=0.5, max_value=8.0, step=0.5) if st.button("Add Event"): start_datetime = datetime.combine(start_date, start_time) end_datetime = start_datetime + timedelta(hours=duration) event_data = { "subject": subject, "start": { "dateTime": start_datetime.isoformat(), "timeZone": "UTC" }, "end": { "dateTime": end_datetime.isoformat(), "timeZone": "UTC" } } result = make_api_call('me/events', token, method='POST', data=event_data) if result: st.success("Event added successfully!") else: st.error("Failed to add event.") if __name__ == "__main__": main()