Spaces:
Sleeping
Sleeping
| import os | |
| import streamlit as st | |
| import requests | |
| import msal | |
| from datetime import datetime, timedelta | |
| import calendar | |
| # Configuration | |
| APPLICATION_ID_KEY = os.getenv('APPLICATION_ID_KEY') | |
| CLIENT_SECRET_KEY = os.getenv('CLIENT_SECRET_KEY') | |
| AUTHORITY_URL = 'https://login.microsoftonline.com/common' | |
| REDIRECT_URI = 'https://huggingface.co/spaces/awacke1/MSGraphAPI' | |
| def sticky_menu(): | |
| st.markdown( | |
| """ | |
| <style> | |
| .menu-bar { | |
| position: -webkit-sticky; | |
| position: sticky; | |
| top: 0; | |
| background-color: white; | |
| z-index: 999; | |
| padding: 10px; | |
| border-bottom: 1px solid #f0f0f0; | |
| } | |
| .menu-bar a { | |
| margin: 0 10px; | |
| padding: 5px; | |
| text-decoration: none; | |
| color: #000; | |
| } | |
| .menu-bar a:hover { | |
| background-color: #f0f0f0; | |
| } | |
| </style> | |
| <div class="menu-bar"> | |
| <a href="#dashboard">1️⃣ Dashboard</a> | |
| <a href="#landing-page">🏠 Landing Page</a> | |
| <a href="#upcoming-events">📅 Upcoming Events</a> | |
| <a href="#schedule">📆 Schedule</a> | |
| <a href="#agenda">📝 Agenda</a> | |
| <a href="#event-details">🔍 Event Details</a> | |
| <a href="#add-event">➕ Add Event</a> | |
| <a href="#filter-by">🔎 Filter By</a> | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| def dashboard(access_token): | |
| st.subheader("1️⃣ Dashboard") | |
| # Timeframe selector | |
| timeframe = st.selectbox("Select Timeframe", ["Day", "Week", "Month"]) | |
| now = datetime.now() | |
| if timeframe == "Day": | |
| start_time = now.replace(hour=0, minute=0, second=0) | |
| end_time = now.replace(hour=23, minute=59, second=59) | |
| elif timeframe == "Week": | |
| start_time = now - timedelta(days=now.weekday()) # Start of the week (Monday) | |
| end_time = start_time + timedelta(days=6) | |
| elif timeframe == "Month": | |
| start_time = now.replace(day=1, hour=0, minute=0, second=0) | |
| next_month = (now.month % 12) + 1 | |
| end_time = start_time.replace(month=next_month, day=1) - timedelta(days=1) | |
| # Fetch and display calendar events for the selected timeframe | |
| events = make_api_call(access_token, f"me/calendarView?startDateTime={start_time.isoformat()}&endDateTime={end_time.isoformat()}&$orderby=start/dateTime") | |
| if events and 'value' in events: | |
| st.write(f"📅 Events from {start_time.date()} to {end_time.date()}") | |
| for event in events['value']: | |
| start_date = datetime.fromisoformat(event['start']['dateTime'][:-1]) | |
| st.write(f"**{event['subject']}** | {start_date.strftime('%Y-%m-%d %H:%M')}") | |
| st.write("---") | |
| else: | |
| st.write("No events found or unable to fetch events.") | |
| def landing_page(): | |
| st.subheader("🏠 Landing Page") | |
| st.write("Welcome to the app! Use the menu above to navigate.") | |
| def upcoming_events(access_token): | |
| st.subheader("📅 Upcoming Events") | |
| # Show upcoming events from the current date | |
| now = datetime.now() | |
| events = make_api_call(access_token, f"me/calendar/events?$top=10&$orderby=start/dateTime&$filter=start/dateTime ge {now.isoformat()}") | |
| if events and 'value' in events: | |
| st.write("Upcoming Events:") | |
| for event in events['value']: | |
| start_date = datetime.fromisoformat(event['start']['dateTime'][:-1]) | |
| st.write(f"**{event['subject']}** | {start_date.strftime('%Y-%m-%d %H:%M')}") | |
| st.write("---") | |
| else: | |
| st.write("No upcoming events.") | |
| def schedule(access_token): | |
| st.subheader("📆 Schedule") | |
| # Display a weekly or daily schedule from the current date | |
| now = datetime.now() | |
| week_start = now - timedelta(days=now.weekday()) # Start of the week (Monday) | |
| week_end = week_start + timedelta(days=6) | |
| st.write(f"Schedule for the week {week_start.strftime('%Y-%m-%d')} to {week_end.strftime('%Y-%m-%d')}") | |
| events = make_api_call(access_token, f"me/calendarView?startDateTime={week_start.isoformat()}&endDateTime={week_end.isoformat()}&$orderby=start/dateTime") | |
| if events and 'value' in events: | |
| for event in events['value']: | |
| start_date = datetime.fromisoformat(event['start']['dateTime'][:-1]) | |
| st.write(f"**{event['subject']}** | {start_date.strftime('%Y-%m-%d %H:%M')}") | |
| st.write("---") | |
| else: | |
| st.write("No events found.") | |
| def agenda(access_token): | |
| st.subheader("📝 Agenda") | |
| # Display a list of tasks or meetings | |
| tasks = make_api_call(access_token, 'me/todo/lists') | |
| if tasks and 'value' in tasks: | |
| st.write("Agenda Items:") | |
| for task in tasks['value']: | |
| st.write(f"Task: {task['title']}") | |
| st.write("---") | |
| else: | |
| st.write("No tasks or agenda items.") | |
| def event_details(access_token): | |
| st.subheader("🔍 Event Details") | |
| # Fetch and display details for a specific event | |
| event_id = st.text_input("Enter Event ID") | |
| if event_id: | |
| event = make_api_call(access_token, f'me/events/{event_id}') | |
| if event: | |
| st.write(f"Event: {event['subject']}") | |
| st.write(f"Start: {event['start']['dateTime']}") | |
| st.write(f"End: {event['end']['dateTime']}") | |
| st.write(f"Description: {event.get('bodyPreview', 'No description')}") | |
| else: | |
| st.write("Unable to fetch event details.") | |
| def add_event(access_token): | |
| st.subheader("➕ Add Event") | |
| # Create event | |
| event_subject = st.text_input("Event Subject") | |
| event_date = st.date_input("Event Date") | |
| event_time = st.time_input("Event Time") | |
| if st.button("Add Event"): | |
| event_start = datetime.combine(event_date, event_time) | |
| event_end = event_start + timedelta(hours=1) | |
| new_event = { | |
| "subject": event_subject, | |
| "start": { | |
| "dateTime": event_start.isoformat(), | |
| "timeZone": "UTC" | |
| }, | |
| "end": { | |
| "dateTime": event_end.isoformat(), | |
| "timeZone": "UTC" | |
| } | |
| } | |
| result = make_api_call(access_token, 'me/events', method='POST', data=new_event) | |
| if result: | |
| st.success("Event added successfully!") | |
| else: | |
| st.error("Failed to add event.") | |
| def filter_by(access_token): | |
| st.subheader("🔎 Filter By") | |
| # Filter calendar events by title, date range, or organizer | |
| filter_by_title = st.text_input("Event Title Contains") | |
| filter_by_start_date = st.date_input("Start Date After", datetime.now() - timedelta(days=30)) | |
| filter_by_end_date = st.date_input("End Date Before", datetime.now() + timedelta(days=30)) | |
| filters = [] | |
| if filter_by_title: | |
| filters.append(f"contains(subject, '{filter_by_title}')") | |
| if filter_by_start_date: | |
| filters.append(f"start/dateTime ge {filter_by_start_date.isoformat()}T00:00:00Z") | |
| if filter_by_end_date: | |
| filters.append(f"end/dateTime le {filter_by_end_date.isoformat()}T23:59:59Z") | |
| filter_query = " and ".join(filters) if filters else '' | |
| events_endpoint = f"me/calendarView?startDateTime={filter_by_start_date.isoformat()}&endDateTime={filter_by_end_date.isoformat()}&$orderby=start/dateTime" | |
| if filter_query: | |
| events_endpoint += f"&$filter={filter_query}" | |
| events = make_api_call(access_token, events_endpoint) | |
| if events and 'value' in events: | |
| for event in events['value']: | |
| start_date = datetime.fromisoformat(event['start']['dateTime'][:-1]) | |
| st.write(f"**{event['subject']}** | {start_date.strftime('%Y-%m-%d %H:%M')}") | |
| st.write("---") | |
| else: | |
| st.write("No events found.") | |
| ProductNaming=''' | |
| 🌌🔗 Git Cosmos Glow: Graph & Mobile Flow 📱💫 | |
| 🚀📊 Cosmic Git Wit: Graph Power, Mobile Hit 📲✨ | |
| 🌠🔧 Git Galaxy Gear: Graph Magic, Mobile Clear 📱🎩 | |
| 🌌🔍 Cosmos Code Quest: Graph Zest, Mobile Best 📲🏆 | |
| 🚀💾 Git Star Suite: Graph Might, Mobile Delight 📱✨ | |
| 🌠🔗 Cosmic Link Sync: Graph Blink, Mobile Think 📲💡 | |
| 🌌🛠️ Git Nebula Tools: Graph Rules, Mobile Cools 📱❄️ | |
| 🚀🔮 Cosmos Code Charm: Graph Farm, Mobile Arm 📲💪 | |
| 🌠🔍 Git Galaxy Sight: Graph Bright, Mobile Light 📱💡 | |
| 🌌🚀 Cosmic Git Flight: Graph Insight, Mobile Might 📲💥 | |
| "1️⃣ Dashboard", | |
| "🏠 Landing Page", | |
| "📅 Upcoming Events", | |
| "📆 Schedule", | |
| "📝 Agenda", | |
| "🔍 Event Details", | |
| "➕ Add Event", | |
| "🔎 Filter By" | |
| ''' | |
| # Define product to scope mapping, links, AI capabilities, and Graph solutions | |
| PRODUCT_SCOPES = { | |
| "📧 Outlook": { | |
| 'scopes': ['Mail.Read', 'Mail.Send'], | |
| 'link': 'https://outlook.office.com/mail/', | |
| 'ai_capabilities': "🤖✍️ Smart email & scheduling", | |
| 'graph_solution': "📨📅 Mail, calendar & contacts API" | |
| }, | |
| "📅 Calendar": { | |
| 'scopes': ['Calendars.ReadWrite'], | |
| 'link': 'https://outlook.office.com/calendar/', | |
| 'ai_capabilities': "🤖📅 Smart scheduling & reminders", | |
| 'graph_solution': "📅 Calendar management API" | |
| }, | |
| "📋 Tasks": { | |
| 'scopes': ['Tasks.ReadWrite'], | |
| 'link': 'https://to-do.office.com/tasks/', | |
| 'ai_capabilities': "🤖📝 Task prioritization", | |
| 'graph_solution': "✅ Task management API" | |
| }, | |
| "🗂️ OneDrive": { | |
| 'scopes': ['Files.ReadWrite.All'], | |
| 'link': 'https://onedrive.live.com/', | |
| 'ai_capabilities': "🤖🔍 Smart file organization", | |
| 'graph_solution': "📁 File & folder API" | |
| }, | |
| "📒 OneNote": { | |
| 'scopes': ['Notes.Read', 'Notes.Create'], | |
| 'link': 'https://www.onenote.com/notebooks', | |
| 'ai_capabilities': "🤖📝 Content suggestion & OCR", | |
| 'graph_solution': "📔 Notebook & page API" | |
| }, | |
| "📊 Excel": { | |
| 'scopes': ['Files.ReadWrite.All'], | |
| 'link': 'https://www.office.com/launch/excel', | |
| 'ai_capabilities': "🤖📈 Data analysis & insights", | |
| 'graph_solution': "📊 Workbook & chart API" | |
| }, | |
| "📄 Word": { | |
| 'scopes': ['Files.ReadWrite.All'], | |
| 'link': 'https://www.office.com/launch/word', | |
| 'ai_capabilities': "🤖✍️ Smart drafting & editing", | |
| 'graph_solution': "📝 Document content API" | |
| }, | |
| "🗃️ SharePoint": { | |
| 'scopes': ['Sites.Read.All', 'Sites.ReadWrite.All'], | |
| 'link': 'https://www.microsoft.com/microsoft-365/sharepoint/collaboration', | |
| 'ai_capabilities': "🤖🔍 Smart search & tagging", | |
| 'graph_solution': "🌐 Sites & lists API" | |
| }, | |
| "📅 Teams": { | |
| 'scopes': ['Team.ReadBasic.All', 'Channel.ReadBasic.All'], | |
| 'link': 'https://teams.microsoft.com/', | |
| 'ai_capabilities': "🤖💬 Meeting insights & summaries", | |
| 'graph_solution': "👥 Teams & chats API" | |
| }, | |
| "💬 Viva": { | |
| 'scopes': ['Analytics.Read'], | |
| 'link': 'https://www.microsoft.com/microsoft-viva', | |
| 'ai_capabilities': "🤖📊 Personalized insights", | |
| 'graph_solution': "📈 Analytics & learning API" | |
| }, | |
| "🚀 Power Platform": { | |
| 'scopes': ['Flow.Read.All'], | |
| 'link': 'https://powerplatform.microsoft.com/', | |
| 'ai_capabilities': "🤖⚙️ AI-powered automation", | |
| 'graph_solution': "🔧 Workflow & app API" | |
| }, | |
| "🧠 Copilot": { | |
| 'scopes': ['Cognitive.Read'], | |
| 'link': 'https://www.microsoft.com/microsoft-365/copilot', | |
| 'ai_capabilities': "🤖🚀 Cross-app AI assistance", | |
| 'graph_solution': "🧠 AI integration API" | |
| }, | |
| "💡 PowerPoint": { | |
| 'scopes': ['Files.ReadWrite.All'], | |
| 'link': 'https://www.office.com/launch/powerpoint', | |
| 'ai_capabilities': "🤖🎨 Design & coaching AI", | |
| 'graph_solution': "📊 Presentation API" | |
| }, | |
| "📚 Microsoft Bookings": { | |
| 'scopes': ['Bookings.Read.All', 'Bookings.ReadWrite.All'], | |
| 'link': 'https://outlook.office.com/bookings/', | |
| 'ai_capabilities': "🤖📅 Smart scheduling", | |
| 'graph_solution': "📆 Booking services API" | |
| }, | |
| "📓 Loop": { | |
| 'scopes': ['Files.ReadWrite.All'], | |
| 'link': 'https://loop.microsoft.com/', | |
| 'ai_capabilities': "🤖🔄 Real-time collaboration AI", | |
| 'graph_solution': "🔁 Workspace API" | |
| }, | |
| "🗣️ Translator": { | |
| 'scopes': ['Translation.Read'], | |
| 'link': 'https://www.microsoft.com/translator/', | |
| 'ai_capabilities': "🤖🌐 Real-time translation", | |
| 'graph_solution': "🗨️ Translation services API" | |
| }, | |
| "📋 To Do & Planner": { | |
| 'scopes': ['Tasks.ReadWrite'], | |
| 'link': 'https://todo.microsoft.com/', | |
| 'ai_capabilities': "🤖📝 Smart task management", | |
| 'graph_solution': "✅ Task & plan API" | |
| }, | |
| "🔗 Azure OpenAI Service": { | |
| 'scopes': ['AzureAIServices.ReadWrite.All'], | |
| 'link': 'https://azure.microsoft.com/products/cognitive-services/openai-service/', | |
| 'ai_capabilities': "🤖🧠 Custom AI model access", | |
| 'graph_solution': "🔌 AI model integration API" | |
| } | |
| } | |
| BASE_SCOPES = ['User.Read'] | |
| def get_msal_app(): | |
| return msal.ConfidentialClientApplication( | |
| client_id=APPLICATION_ID_KEY, | |
| client_credential=CLIENT_SECRET_KEY, | |
| authority=AUTHORITY_URL | |
| ) | |
| def get_access_token(code): | |
| client_instance = get_msal_app() | |
| try: | |
| result = client_instance.acquire_token_by_authorization_code( | |
| code=code, | |
| scopes=st.session_state.get('request_scopes', BASE_SCOPES), | |
| redirect_uri=REDIRECT_URI | |
| ) | |
| if 'access_token' in result: | |
| return result['access_token'] | |
| else: | |
| raise Exception(f"Error acquiring token: {result.get('error_description')}") | |
| except Exception as e: | |
| st.error(f"Exception in get_access_token: {str(e)}") | |
| raise | |
| def make_api_call(access_token, endpoint, method='GET', data=None): | |
| headers = {'Authorization': f'Bearer {access_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 | |
| def handle_outlook_integration(access_token): | |
| st.subheader("📧 Outlook Integration") | |
| st.markdown(f"[Open Outlook]({PRODUCT_SCOPES['📧 Outlook']['link']})") | |
| # Filters for emails | |
| st.write("### Filter Emails:") | |
| filter_by_sender = st.text_input("Sender Email") | |
| filter_by_subject = st.text_input("Subject Contains") | |
| filter_by_date = st.date_input("Emails received after", datetime.now() - timedelta(days=30)) | |
| # Create query filters | |
| filters = [] | |
| if filter_by_sender: | |
| filters.append(f"from/emailAddress/address eq '{filter_by_sender}'") | |
| if filter_by_subject: | |
| filters.append(f"contains(subject, '{filter_by_subject}')") | |
| if filter_by_date: | |
| filters.append(f"receivedDateTime ge {filter_by_date.isoformat()}T00:00:00Z") | |
| filter_query = " and ".join(filters) if filters else '' | |
| # Fetch emails with applied filters | |
| emails_endpoint = 'me/messages?$top=10' | |
| if filter_query: | |
| emails_endpoint += f"&$filter={filter_query}&$orderby=receivedDateTime desc" | |
| emails = make_api_call(access_token, emails_endpoint) | |
| if emails and 'value' in emails: | |
| for email in emails['value']: | |
| with st.expander(f"From: {email['from']['emailAddress']['name']} - Subject: {email['subject']}"): | |
| st.write(f"Received: {email['receivedDateTime']}") | |
| st.write(f"Body: {email['bodyPreview']}") | |
| else: | |
| st.write("No emails found or unable to fetch emails.") | |
| def handle_outlook_integration_old(access_token): | |
| st.subheader("📧 Outlook Integration") | |
| st.markdown(f"[Open Outlook]({PRODUCT_SCOPES['📧 Outlook']['link']})") | |
| # Read emails | |
| emails = make_api_call(access_token, 'me/messages?$top=10&$orderby=receivedDateTime desc') | |
| if emails and 'value' in emails: | |
| for email in emails['value']: | |
| with st.expander(f"From: {email['from']['emailAddress']['name']} - Subject: {email['subject']}"): | |
| st.write(f"Received: {email['receivedDateTime']}") | |
| st.write(f"Body: {email['bodyPreview']}") | |
| else: | |
| st.write("No emails found or unable to fetch emails.") | |
| # Create (Send) email | |
| st.write("Send a new email:") | |
| recipient = st.text_input("Recipient Email") | |
| subject = st.text_input("Subject") | |
| body = st.text_area("Body") | |
| if st.button("Send Email"): | |
| new_email = { | |
| "message": { | |
| "subject": subject, | |
| "body": { | |
| "contentType": "Text", | |
| "content": body | |
| }, | |
| "toRecipients": [ | |
| { | |
| "emailAddress": { | |
| "address": recipient | |
| } | |
| } | |
| ] | |
| } | |
| } | |
| result = make_api_call(access_token, 'me/sendMail', method='POST', data=new_email) | |
| if result is None: # sendMail doesn't return content on success | |
| st.success("Email sent successfully!") | |
| else: | |
| st.error("Failed to send email.") | |
| # Update email (mark as read) | |
| st.write("Mark an email as read:") | |
| email_id = st.text_input("Enter Email ID") | |
| if st.button("Mark as Read"): | |
| update_data = { | |
| "isRead": True | |
| } | |
| result = make_api_call(access_token, f'me/messages/{email_id}', method='PATCH', data=update_data) | |
| if result is None: # PATCH doesn't return content on success | |
| st.success("Email marked as read!") | |
| else: | |
| st.error("Failed to mark email as read.") | |
| # Delete email | |
| st.write("Delete an email:") | |
| email_id = st.text_input("Enter Email ID to delete") | |
| if st.button("Delete Email"): | |
| result = make_api_call(access_token, f'me/messages/{email_id}', method='DELETE') | |
| if result is None: # DELETE doesn't return content on success | |
| st.success("Email deleted successfully!") | |
| else: | |
| st.error("Failed to delete email.") | |
| def handle_calendar_integration(access_token): | |
| st.subheader("📅 Calendar Integration") | |
| st.markdown(f"[Open Calendar]({PRODUCT_SCOPES['📅 Calendar']['link']})") | |
| # Filters for calendar events | |
| st.write("### Filter Calendar Events:") | |
| filter_by_title = st.text_input("Event Title Contains") | |
| filter_by_start_date = st.date_input("Start Date After", datetime.now() - timedelta(days=30)) | |
| filter_by_end_date = st.date_input("End Date Before", datetime.now() + timedelta(days=30)) | |
| # Create query filters | |
| filters = [] | |
| if filter_by_title: | |
| filters.append(f"contains(subject, '{filter_by_title}')") | |
| if filter_by_start_date: | |
| filters.append(f"start/dateTime ge {filter_by_start_date.isoformat()}T00:00:00Z") | |
| if filter_by_end_date: | |
| filters.append(f"end/dateTime le {filter_by_end_date.isoformat()}T23:59:59Z") | |
| filter_query = " and ".join(filters) if filters else '' | |
| # Fetch events with applied filters | |
| events_endpoint = f"me/calendarView?startDateTime={filter_by_start_date.isoformat()}T00:00:00&endDateTime={filter_by_end_date.isoformat()}T23:59:59" | |
| if filter_query: | |
| events_endpoint += f"&$filter={filter_query}&$orderby=start/dateTime" | |
| events = make_api_call(access_token, events_endpoint) | |
| if events and 'value' in events: | |
| st.write("### Upcoming Events") | |
| for event in events['value']: | |
| start_date = datetime.fromisoformat(event['start']['dateTime'][:-1]) # Remove 'Z' from the end | |
| st.write(f"**{event['subject']}** | {start_date.strftime('%Y-%m-%d %H:%M')}") | |
| st.write("---") | |
| else: | |
| st.write("No events found or unable to fetch events.") | |
| def handle_calendar_integration_old(access_token): | |
| st.subheader("📅 Calendar Integration") | |
| st.markdown(f"[Open Calendar]({PRODUCT_SCOPES['📅 Calendar']['link']})") | |
| # Get the current month's start and end dates | |
| now = datetime.now() | |
| start_of_month = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0) | |
| end_of_month = start_of_month.replace(month=start_of_month.month % 12 + 1, day=1) - timedelta(days=1) | |
| events = make_api_call(access_token, f"me/calendarView?startDateTime={start_of_month.isoformat()}&endDateTime={end_of_month.isoformat()}&$orderby=start/dateTime") | |
| if events and 'value' in events: | |
| # Create a calendar view | |
| cal = calendar.monthcalendar(now.year, now.month) | |
| st.write(f"Calendar for {now.strftime('%B %Y')}") | |
| # Create a placeholder for each day | |
| day_placeholders = {} | |
| for week in cal: | |
| cols = st.columns(7) | |
| for i, day in enumerate(week): | |
| if day != 0: | |
| day_placeholders[day] = cols[i].empty() | |
| day_placeholders[day].write(f"**{day}**") | |
| # Populate the calendar with events | |
| for event in events['value']: | |
| start_date = datetime.fromisoformat(event['start']['dateTime'][:-1]) # Remove 'Z' from the end | |
| day = start_date.day | |
| if day in day_placeholders: | |
| day_placeholders[day].write(f"{start_date.strftime('%H:%M')} - {event['subject']}") | |
| else: | |
| st.write("No events found or unable to fetch events.") | |
| # Create event | |
| st.write("Add a new event:") | |
| event_subject = st.text_input("Event Subject") | |
| event_date = st.date_input("Event Date") | |
| event_time = st.time_input("Event Time") | |
| if st.button("Add Event"): | |
| event_start = datetime.combine(event_date, event_time) | |
| event_end = event_start + timedelta(hours=1) | |
| new_event = { | |
| "subject": event_subject, | |
| "start": { | |
| "dateTime": event_start.isoformat(), | |
| "timeZone": "UTC" | |
| }, | |
| "end": { | |
| "dateTime": event_end.isoformat(), | |
| "timeZone": "UTC" | |
| } | |
| } | |
| result = make_api_call(access_token, 'me/events', method='POST', data=new_event) | |
| if result: | |
| st.success("Event added successfully!") | |
| else: | |
| st.error("Failed to add event.") | |
| # Update event | |
| st.write("Update an event:") | |
| event_id = st.text_input("Enter Event ID") | |
| new_subject = st.text_input("New Subject") | |
| if st.button("Update Event"): | |
| update_data = { | |
| "subject": new_subject | |
| } | |
| result = make_api_call(access_token, f'me/events/{event_id}', method='PATCH', data=update_data) | |
| if result is None: # PATCH doesn't return content on success | |
| st.success("Event updated successfully!") | |
| else: | |
| st.error("Failed to update event.") | |
| # Delete event | |
| st.write("Delete an event:") | |
| event_id_to_delete = st.text_input("Enter Event ID to delete") | |
| if st.button("Delete Event"): | |
| result = make_api_call(access_token, f'me/events/{event_id_to_delete}', method='DELETE') | |
| if result is None: # DELETE doesn't return content on success | |
| st.success("Event deleted successfully!") | |
| else: | |
| st.error("Failed to delete event.") | |
| def handle_tasks_integration(access_token): | |
| st.subheader("📋 Tasks Integration") | |
| st.markdown(f"[Open Tasks]({PRODUCT_SCOPES['📋 Tasks']['link']})") | |
| # Read tasks | |
| tasks = make_api_call(access_token, 'me/todo/lists') | |
| if tasks and 'value' in tasks: | |
| default_list = next((list for list in tasks['value'] if list['wellknownListName'] == 'defaultList'), None) | |
| if default_list: | |
| tasks = make_api_call(access_token, f"me/todo/lists/{default_list['id']}/tasks") | |
| if tasks and 'value' in tasks: | |
| for task in tasks['value']: | |
| st.write(f"Task: {task['title']}") | |
| st.write(f"Status: {'Completed' if task['status'] == 'completed' else 'Not Completed'}") | |
| st.write("---") | |
| else: | |
| st.write("No tasks found or unable to fetch tasks.") | |
| else: | |
| st.write("Default task list not found.") | |
| else: | |
| st.write("Unable to fetch task lists.") | |
| # Create task | |
| st.write("Add a new task:") | |
| task_title = st.text_input("Task Title") | |
| if st.button("Add Task"): | |
| new_task = { | |
| "title": task_title | |
| } | |
| result = make_api_call(access_token, f"me/todo/lists/{default_list['id']}/tasks", method='POST', data=new_task) | |
| if result: | |
| st.success("Task added successfully!") | |
| else: | |
| st.error("Failed to add task.") | |
| # Update task | |
| st.write("Update a task:") | |
| task_id = st.text_input("Enter Task ID") | |
| new_title = st.text_input("New Title") | |
| if st.button("Update Task"): | |
| update_data = { | |
| "title": new_title | |
| } | |
| result = make_api_call(access_token, f"me/todo/lists/{default_list['id']}/tasks/{task_id}", method='PATCH', data=update_data) | |
| if result is None: # PATCH doesn't return content on success | |
| st.success("Task updated successfully!") | |
| else: | |
| st.error("Failed to update task.") | |
| # Delete task | |
| st.write("Delete a task:") | |
| task_id_to_delete = st.text_input("Enter Task ID to delete") | |
| if st.button("Delete Task"): | |
| result = make_api_call(access_token, f"me/todo/lists/{default_list['id']}/tasks/{task_id_to_delete}", method='DELETE') | |
| if result is None: # DELETE doesn't return content on success | |
| st.success("Task deleted successfully!") | |
| else: | |
| st.error("Failed to delete task.") | |
| def handle_onedrive_integration(access_token): | |
| st.subheader("🗂️ OneDrive Integration") | |
| st.markdown(f"[Open OneDrive]({PRODUCT_SCOPES['🗂️ OneDrive']['link']})") | |
| # Read files | |
| files = make_api_call(access_token, 'me/drive/root/children') | |
| if files and 'value' in files: | |
| for file in files['value']: | |
| st.write(f"Name: {file['name']}") | |
| st.write(f"Type: {'Folder' if 'folder' in file else 'File'}") | |
| st.write(f"Last Modified: {file['lastModifiedDateTime']}") | |
| st.write("---") | |
| else: | |
| st.write("No files found or unable to fetch files.") | |
| # Create file | |
| st.write("Create a new text file:") | |
| file_name = st.text_input("File Name (include .txt extension)") | |
| file_content = st.text_area("File Content") | |
| if st.button("Create File"): | |
| create_file_url = f"https://graph.microsoft.com/v1.0/me/drive/root:/{file_name}:/content" | |
| headers = { | |
| 'Authorization': f'Bearer {access_token}', | |
| 'Content-Type': 'text/plain' | |
| } | |
| response = requests.put(create_file_url, headers=headers, data=file_content.encode('utf-8')) | |
| if response.status_code == 201: | |
| st.success("File created successfully!") | |
| else: | |
| st.error("Failed to create file.") | |
| # Update file | |
| st.write("Update a file:") | |
| file_path = st.text_input("File Path (e.g., /Documents/file.txt)") | |
| new_content = st.text_area("New Content") | |
| if st.button("Update File"): | |
| update_file_url = f"https://graph.microsoft.com/v1.0/me/drive/root:{file_path}:/content" | |
| headers = { | |
| 'Authorization': f'Bearer {access_token}', | |
| 'Content-Type': 'text/plain' | |
| } | |
| response = requests.put(update_file_url, headers=headers, data=new_content.encode('utf-8')) | |
| if response.status_code == 200: | |
| st.success("File updated successfully!") | |
| else: | |
| st.error("Failed to update file.") | |
| # Delete file | |
| st.write("Delete a file:") | |
| file_path_to_delete = st.text_input("File Path to delete (e.g., /Documents/file.txt)") | |
| if st.button("Delete File"): | |
| result = make_api_call(access_token, f"me/drive/root:{file_path_to_delete}", method='DELETE') | |
| if result is None: # DELETE doesn't return content on success | |
| st.success("File deleted successfully!") | |
| else: | |
| st.error("Failed to delete file.") | |
| def main(): | |
| st.title("🦄 MS Graph API with AI & Cloud Integration for M365") | |
| # Sticky Menu | |
| sticky_menu() | |
| # Sidebar Menu for Product Selection | |
| st.sidebar.title("📝 M365 Products") | |
| st.sidebar.write("Select products to integrate:") | |
| selected_products = {} | |
| for product, details in PRODUCT_SCOPES.items(): | |
| selected = st.sidebar.checkbox(product) | |
| if selected: | |
| selected_products[product] = True | |
| st.sidebar.write(f"AI Capabilities: {details['ai_capabilities']}") | |
| st.sidebar.write(f"Graph Solution: {details['graph_solution']}") | |
| # Handle query parameters via session_state | |
| if 'section' not in st.session_state: | |
| st.session_state['section'] = 'dashboard' # Default section is the dashboard | |
| selected_section = st.session_state['section'] | |
| # Example of re-running based on interaction (you can change sections) | |
| if st.button("Go to Landing Page"): | |
| st.session_state['section'] = 'landing-page' | |
| # Request scopes and authentication management | |
| request_scopes = BASE_SCOPES.copy() | |
| for product in selected_products: | |
| request_scopes.extend(PRODUCT_SCOPES[product]['scopes']) | |
| request_scopes = list(set(request_scopes)) | |
| st.session_state['request_scopes'] = request_scopes | |
| if 'access_token' not in st.session_state: | |
| client_instance = get_msal_app() | |
| auth_url = client_instance.get_authorization_request_url( | |
| scopes=request_scopes, | |
| redirect_uri=REDIRECT_URI | |
| ) | |
| st.write('👋 Please [click here]({}) to log in and authorize the app.'.format(auth_url)) | |
| query_params = st.session_state.get('query_params', {}) | |
| if 'code' in query_params: | |
| code = query_params.get('code') | |
| st.write('🔑 Authorization Code Obtained:', code[:10] + '...') | |
| try: | |
| access_token = get_access_token(code) | |
| st.session_state['access_token'] = access_token | |
| st.success("Access token acquired successfully!") | |
| # No need for st.experimental_rerun; changing session state triggers rerun | |
| st.session_state['section'] = 'dashboard' | |
| except Exception as e: | |
| st.error(f"Error acquiring access token: {str(e)}") | |
| st.stop() | |
| else: | |
| access_token = st.session_state['access_token'] | |
| user_info = make_api_call(access_token, 'me') | |
| if user_info: | |
| st.sidebar.write(f"👋 Hello, {user_info.get('displayName', 'User')}!") | |
| # Handle navigation based on the selected section | |
| if selected_section == 'dashboard': | |
| dashboard(access_token) | |
| elif selected_section == 'landing-page': | |
| landing_page() | |
| elif selected_section == 'upcoming-events': | |
| upcoming_events(access_token) | |
| elif selected_section == 'schedule': | |
| schedule(access_token) | |
| elif selected_section == 'agenda': | |
| agenda(access_token) | |
| elif selected_section == 'event-details': | |
| event_details(access_token) | |
| elif selected_section == 'add-event': | |
| add_event(access_token) | |
| elif selected_section == 'filter-by': | |
| filter_by(access_token) | |
| if __name__ == "__main__": | |
| main() | |