|
4 | 4 | from typing import Optional, Dict |
5 | 5 | from dataclasses import dataclass |
6 | 6 | from datetime import datetime, timedelta |
7 | | -from starlette.responses import HTMLResponse, RedirectResponse |
| 7 | +from starlette.responses import HTMLResponse, RedirectResponse, Response |
| 8 | +from starlette.templating import Jinja2Templates |
8 | 9 | from starlette.requests import Request |
9 | 10 | from starlette.routing import Route |
10 | | -from starlette.responses import Response |
11 | 11 | from app.mcp.logger import get_logger |
12 | 12 |
|
13 | 13 |
|
14 | 14 | logger = get_logger(__name__) |
15 | 15 |
|
| 16 | +templates = Jinja2Templates(directory=os.path.join(os.path.dirname(__file__), "templates")) |
16 | 17 |
|
17 | 18 | @dataclass |
18 | 19 | class OAuthConfig: |
@@ -270,86 +271,7 @@ async def get_valid_token(self, session_id: str) -> Optional[OAuthToken]: |
270 | 271 |
|
271 | 272 | def create_oauth_routes(self) -> list: |
272 | 273 | async def oauth_login(request: Request) -> Response: |
273 | | - html_content = """ |
274 | | - <!DOCTYPE html> |
275 | | - <html> |
276 | | - <head> |
277 | | - <title>CMS MCP Server - Login</title> |
278 | | - <style> |
279 | | - body { |
280 | | - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; |
281 | | - display: flex; |
282 | | - justify-content: center; |
283 | | - align-items: center; |
284 | | - min-height: 100vh; |
285 | | - margin: 0; |
286 | | - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
287 | | - } |
288 | | - .login-container { |
289 | | - background: white; |
290 | | - padding: 2rem; |
291 | | - border-radius: 10px; |
292 | | - box-shadow: 0 10px 25px rgba(0,0,0,0.2); |
293 | | - text-align: center; |
294 | | - max-width: 400px; |
295 | | - width: 90%; |
296 | | - box-sizing: border-box; |
297 | | - } |
298 | | - h1 { |
299 | | - color: #333; |
300 | | - margin-bottom: 0.5rem; |
301 | | - } |
302 | | - p { |
303 | | - color: #666; |
304 | | - margin-bottom: 2rem; |
305 | | - } |
306 | | - .btn-oauth { |
307 | | - display: flex; |
308 | | - align-items: center; |
309 | | - justify-content: center; |
310 | | - width: 100%; |
311 | | - padding: 12px 20px; |
312 | | - margin: 10px 0; |
313 | | - border: none; |
314 | | - border-radius: 5px; |
315 | | - font-size: 16px; |
316 | | - font-weight: 500; |
317 | | - cursor: pointer; |
318 | | - text-decoration: none; |
319 | | - transition: transform 0.2s, box-shadow 0.2s; |
320 | | - box-sizing: border-box; |
321 | | - } |
322 | | - .btn-oauth:hover { |
323 | | - transform: translateY(-2px); |
324 | | - box-shadow: 0 5px 15px rgba(0,0,0,0.2); |
325 | | - } |
326 | | - .btn-google { |
327 | | - background: #4285f4; |
328 | | - color: white; |
329 | | - } |
330 | | - .btn-github { |
331 | | - background: #24292e; |
332 | | - color: white; |
333 | | - } |
334 | | - </style> |
335 | | - </head> |
336 | | - <body> |
337 | | - <div class="login-container"> |
338 | | - <h1>🔐 CMS MCP Server</h1> |
339 | | - <p>Sign in to access the MCP server</p> |
340 | | -
|
341 | | - <a href="/oauth/authorize/google" class="btn-oauth btn-google"> |
342 | | - Continue with Google |
343 | | - </a> |
344 | | -
|
345 | | - <a href="/oauth/authorize/github" class="btn-oauth btn-github"> |
346 | | - Continue with GitHub |
347 | | - </a> |
348 | | - </div> |
349 | | - </body> |
350 | | - </html> |
351 | | - """ |
352 | | - return HTMLResponse(content=html_content) |
| 274 | + return templates.TemplateResponse("login.html", {"request": request}) |
353 | 275 |
|
354 | 276 | async def oauth_authorize(request: Request) -> Response: |
355 | 277 | provider = request.path_params['provider'] |
@@ -412,81 +334,16 @@ async def oauth_callback(request: Request) -> Response: |
412 | 334 | user_email = user_info.get("email", "N/A") |
413 | 335 | user_name = user_info.get("name") or user_info.get("login", "User") |
414 | 336 |
|
415 | | - html_content = f""" |
416 | | - <!DOCTYPE html> |
417 | | - <html> |
418 | | - <head> |
419 | | - <title>Authentication Successful</title> |
420 | | - <style> |
421 | | - body {{ |
422 | | - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; |
423 | | - display: flex; |
424 | | - justify-content: center; |
425 | | - align-items: center; |
426 | | - min-height: 100vh; |
427 | | - margin: 0; |
428 | | - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
429 | | - }} |
430 | | - .success-container {{ |
431 | | - background: white; |
432 | | - padding: 2rem; |
433 | | - border-radius: 10px; |
434 | | - box-shadow: 0 10px 25px rgba(0,0,0,0.2); |
435 | | - text-align: center; |
436 | | - max-width: 500px; |
437 | | - }} |
438 | | - h1 {{ |
439 | | - color: #333; |
440 | | - }} |
441 | | - .user-info {{ |
442 | | - background: #f5f5f5; |
443 | | - padding: 1rem; |
444 | | - border-radius: 5px; |
445 | | - margin: 1rem 0; |
446 | | - }} |
447 | | - .token-info {{ |
448 | | - background: #e8f5e9; |
449 | | - padding: 1rem; |
450 | | - border-radius: 5px; |
451 | | - margin: 1rem 0; |
452 | | - word-break: break-all; |
453 | | - font-family: monospace; |
454 | | - font-size: 12px; |
455 | | - }} |
456 | | - .btn {{ |
457 | | - display: inline-block; |
458 | | - padding: 10px 20px; |
459 | | - background: #667eea; |
460 | | - color: white; |
461 | | - text-decoration: none; |
462 | | - border-radius: 5px; |
463 | | - margin-top: 1rem; |
464 | | - }} |
465 | | - </style> |
466 | | - </head> |
467 | | - <body> |
468 | | - <div class="success-container"> |
469 | | - <div style="font-size: 64px;">✅</div> |
470 | | - <h1>Authentication Successful!</h1> |
471 | | - <div class="user-info"> |
472 | | - <p><strong>Welcome, {user_name}!</strong></p> |
473 | | - <p>Email: {user_email}</p> |
474 | | - <p>Provider: {provider.title()}</p> |
475 | | - </div> |
476 | | - <div class="token-info"> |
477 | | - <p><strong>Session ID:</strong></p> |
478 | | - <p>{session_id}</p> |
479 | | - </div> |
480 | | - <p style="color: #666; font-size: 14px;"> |
481 | | - You can now use the MCP server with your authenticated session. |
482 | | - </p> |
483 | | - <a href="/oauth/status" class="btn">Check Session Status</a> |
484 | | - </div> |
485 | | - </body> |
486 | | - </html> |
487 | | - """ |
488 | | - |
489 | | - response = HTMLResponse(content=html_content) |
| 337 | + response = templates.TemplateResponse( |
| 338 | + "callback.html", |
| 339 | + { |
| 340 | + "request": request, |
| 341 | + "user_name": user_name, |
| 342 | + "user_email": user_email, |
| 343 | + "provider": provider, |
| 344 | + "session_id": session_id, |
| 345 | + } |
| 346 | + ) |
490 | 347 | response.set_cookie( |
491 | 348 | key="cms_mcp_session", |
492 | 349 | value=session_id, |
@@ -518,60 +375,14 @@ async def oauth_status(request: Request) -> Response: |
518 | 375 | if not token: |
519 | 376 | return HTMLResponse(content="<h1>⏰ Session Expired</h1><p>Please login again.</p>") |
520 | 377 |
|
521 | | - html_content = f""" |
522 | | - <!DOCTYPE html> |
523 | | - <html> |
524 | | - <head> |
525 | | - <title>Session Status</title> |
526 | | - <style> |
527 | | - body {{ |
528 | | - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; |
529 | | - display: flex; |
530 | | - justify-content: center; |
531 | | - align-items: center; |
532 | | - min-height: 100vh; |
533 | | - margin: 0; |
534 | | - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
535 | | - }} |
536 | | - .status-container {{ |
537 | | - background: white; |
538 | | - padding: 2rem; |
539 | | - border-radius: 10px; |
540 | | - box-shadow: 0 10px 25px rgba(0,0,0,0.2); |
541 | | - max-width: 500px; |
542 | | - }} |
543 | | - h1 {{ |
544 | | - color: #333; |
545 | | - }} |
546 | | - .info-row {{ |
547 | | - display: flex; |
548 | | - justify-content: space-between; |
549 | | - padding: 0.5rem 0; |
550 | | - border-bottom: 1px solid #eee; |
551 | | - }} |
552 | | - </style> |
553 | | - </head> |
554 | | - <body> |
555 | | - <div class="status-container"> |
556 | | - <h1>✅ Active Session</h1> |
557 | | - <div class="info-row"> |
558 | | - <strong>Session ID:</strong> |
559 | | - <span>{session_id[:16]}...</span> |
560 | | - </div> |
561 | | - <div class="info-row"> |
562 | | - <strong>Token Valid:</strong> |
563 | | - <span>Yes</span> |
564 | | - </div> |
565 | | - <div class="info-row"> |
566 | | - <strong>Expires In:</strong> |
567 | | - <span>{token.expires_in} seconds</span> |
568 | | - </div> |
569 | | - </div> |
570 | | - </body> |
571 | | - </html> |
572 | | - """ |
573 | | - |
574 | | - return HTMLResponse(content=html_content) |
| 378 | + return templates.TemplateResponse( |
| 379 | + "status.html", |
| 380 | + { |
| 381 | + "request": request, |
| 382 | + "session_id": session_id, |
| 383 | + "expires_in": token.expires_in, |
| 384 | + } |
| 385 | + ) |
575 | 386 |
|
576 | 387 | async def oauth_logout(request: Request) -> Response: |
577 | 388 | session_id = request.cookies.get("cms_mcp_session") |
|
0 commit comments