1+ """
2+ Created on 2025-02-15
3+
4+ @author: wf
5+ """
6+
7+ from fastapi .responses import RedirectResponse
8+ from ngwidgets .login import Login
9+ from ngwidgets .webserver import WebSolution , NiceGuiWebserver
10+ from nicegui import Client , ui
11+ from wikibot3rd .sso import User
12+ from wikibot3rd .sso_users import Sso_Users
13+
14+ class SsoSolution (WebSolution ):
15+ """
16+ Encapsulates SSO authentication setup and user handling
17+ """
18+ def __init__ (self , webserver : NiceGuiWebserver , client : Client = None , credentials_path = None ):
19+ """
20+ Initialize SSO authentication
21+
22+ Args:
23+ webserver: The webserver instance to set up SSO for
24+ client: The client instance (can be None for non-client specific solutions)
25+ credentials_path: Optional path to the SSO credentials file
26+ """
27+ super ().__init__ (webserver , client ) # Call parent constructor with both required parameters
28+ self .users = Sso_Users (webserver .config .short_name , credentials_path = credentials_path )
29+
30+ self .login = Login (webserver , self .users )
31+
32+ def get_user (self ) -> User :
33+ """
34+ Get the current authenticated user
35+
36+ Returns:
37+ User: The current user object or None if not authenticated
38+ """
39+ user = None
40+ username = self .login .get_username ()
41+ if username and self .users .is_available :
42+ user = self .users .sso .get_user (username )
43+ return user
44+
45+ def get_user_display_name (self ) -> str :
46+ """
47+ Get the display name for the current user with admin indicator
48+
49+ Returns:
50+ str: Username with optional admin indicator
51+ """
52+ username = self .login .get_username ()
53+ if username is None :
54+ username = "?"
55+ user = self .get_user ()
56+ admin_flag = "🔑" if user and user .is_admin else ""
57+ user_display = f"{ username } { admin_flag } "
58+ return user_display
59+
60+ async def logout (self ):
61+ """Handle user logout"""
62+ await self .login .logout ()
63+
64+ def as_html (self ) -> str :
65+ """
66+ Get the user details as HTML markup
67+
68+ Returns:
69+ str: HTML markup for the user details or error message
70+ """
71+ user = self .get_user ()
72+ html_markup = "<h1>User Details</h1>"
73+ if not user :
74+ html_markup += "<p>No user logged in</p>"
75+ else :
76+ html_markup += f"""
77+ <p><strong>ID:</strong> { user .id } </p>
78+ <p><strong>Name:</strong> { user .name } </p>
79+ <p><strong>Real Name:</strong> { user .real_name } </p>
80+ <p><strong>Email:</strong> { user .email } </p>
81+ <p><strong>Edit Count:</strong> { user .editcount } </p>
82+ """
83+ return html_markup
84+
85+ async def show_login (self ):
86+ """Show the login page"""
87+ await self .login .login (self )
88+
89+ async def show_user_details (self ):
90+ """Show the user details page"""
91+ def show ():
92+ self .logout_button = ui .button (
93+ "logout" , icon = "logout" ,
94+ on_click = self .logout
95+ )
96+ ui .html (self .as_html ())
97+ await self .setup_content_div (show )
98+
99+ def configure_menu (self ):
100+ """Configure the user menu"""
101+ display_name = self .get_user_display_name ()
102+ self .link_button (display_name , "/user" , "person" )
103+ # make sure the link exists
104+ self .register_pages ()
105+
106+ def register_pages (self ):
107+ """Register the SSO-related pages"""
108+ @ui .page ("/user" )
109+ async def show_user (client : Client ):
110+ if not self .login .authenticated ():
111+ return RedirectResponse ("/login" )
112+ return await self .webserver .execute_action (
113+ client ,
114+ solution_class = SsoSolution ,
115+ wanted_action = SsoSolution .show_user_details
116+ )
117+
118+ @ui .page ("/login" )
119+ async def login (client : Client ):
120+ return await self .webserver .execute_action (
121+ client ,
122+ solution_class = SsoSolution ,
123+ wanted_action = SsoSolution .show_login
124+ )
0 commit comments