1919
2020
2121class AdminAccessMixin (ModelView ):
22+ """
23+ Mixin that restricts access to admin model views to ADMIN users only.
24+
25+ Provides ``is_accessible`` and ``is_visible`` checks that ensure only
26+ users with the ``ADMIN`` role can view and interact with the model
27+ in the SQLAdmin panel.
28+ """
29+
2230 def is_accessible (self , request : Request ) -> bool :
31+ """
32+ Check whether the current user has ADMIN role for access control.
33+
34+ Args:
35+ request: The incoming HTTP request with user information attached
36+ to ``request.state``.
37+
38+ Returns:
39+ ``True`` if the authenticated user has the ``ADMIN`` role;
40+ ``False`` otherwise.
41+ """
2342 user = getattr (request .state , 'user' , None )
2443 return user is not None and user .role == UserRole .ADMIN
2544
2645 def is_visible (self , request : Request ) -> bool :
46+ """
47+ Check whether the current user has ADMIN role for menu visibility.
48+
49+ Args:
50+ request: The incoming HTTP request with user information attached
51+ to ``request.state``.
52+
53+ Returns:
54+ ``True`` if the authenticated user has the ``ADMIN`` role;
55+ ``False`` otherwise.
56+ """
2757 user = getattr (request .state , 'user' , None )
2858 return user is not None and user .role == UserRole .ADMIN
2959
3060
3161class AdminPanelFormatter :
62+ """
63+ Utility class providing formatter methods for displaying data in the admin panel.
64+
65+ Each static method produces HTML markup (via ``Markup``) suitable for
66+ use as a SQLAdmin column formatter, rendering badges, links, and
67+ styled status indicators.
68+ """
69+
3270 @staticmethod
3371 def status_formatter (model : Any , name : Any ) -> Any :
72+ """
73+ Render a status field value as a colored Bootstrap badge.
74+
75+ Maps common status and role values to appropriate Bootstrap badge
76+ colors (e.g., ``ACTIVE`` to green, ``CANCELLED`` to red).
77+
78+ Args:
79+ model: The SQLAlchemy model instance being formatted.
80+ name: The attribute name to read from the model (e.g., ``status``,
81+ ``role``, ``target_role``).
82+
83+ Returns:
84+ A ``Markup`` string containing the HTML badge, or the raw
85+ attribute value if the name is not a recognized status field.
86+ """
3487 status_colors = {
3588 'ACTIVE' : 'success' ,
3689 'PENDING' : 'warning' ,
@@ -56,27 +109,76 @@ def status_formatter(model: Any, name: Any) -> Any:
56109
57110 @staticmethod
58111 def user_link_formatter (model : Any , name : Any ) -> Any :
112+ """
113+ Render a user ID as a clickable link to the user detail page.
114+
115+ Args:
116+ model: The SQLAlchemy model instance being formatted.
117+ name: The attribute name holding the user ID.
118+
119+ Returns:
120+ A ``Markup`` anchor tag linking to ``/admin/user/details/<id>``,
121+ or ``'N/A'`` if the user ID is empty.
122+ """
59123 user_id = getattr (model , name )
60124 if not user_id :
61125 return 'N/A'
62126 return Markup (f'<a href="/admin/user/details/{ user_id } ">{ user_id } </a>' )
63127
64128 @staticmethod
65129 def product_link_formatter (model : Any , name : Any ) -> Any :
130+ """
131+ Render a product ID as a clickable link to the product detail page.
132+
133+ Args:
134+ model: The SQLAlchemy model instance being formatted.
135+ name: The attribute name holding the product ID.
136+
137+ Returns:
138+ A ``Markup`` anchor tag linking to ``/admin/product/details/<id>``,
139+ or ``'N/A'`` if the product ID is empty.
140+ """
66141 product_id = getattr (model , name )
67142 if not product_id :
68143 return 'N/A'
69144 return Markup (f'<a href="/admin/product/details/{ product_id } ">{ product_id } </a>' )
70145
71146 @staticmethod
72147 def order_link_formatter (model : Any , name : Any ) -> Any :
148+ """
149+ Render an order ID as a clickable link to the order detail page.
150+
151+ Args:
152+ model: The SQLAlchemy model instance being formatted.
153+ name: The attribute name holding the order ID.
154+
155+ Returns:
156+ A ``Markup`` anchor tag linking to ``/admin/order/details/<id>``,
157+ or ``'N/A'`` if the order ID is empty.
158+ """
73159 order_id = getattr (model , name )
74160 if not order_id :
75161 return 'N/A'
76162 return Markup (f'<a href="/admin/order/details/{ order_id } ">{ order_id } </a>' )
77163
78164 @staticmethod
79165 def docs_link_formatter (model : Any , name : Any ) -> Any :
166+ """
167+ Render verification document keys as clickable links for viewing.
168+
169+ Generates a comma-separated list of anchor tags, each linking to
170+ a verification document endpoint keyed by document type.
171+
172+ Args:
173+ model: The SQLAlchemy model instance being formatted (must have
174+ an ``id`` attribute).
175+ name: The attribute name holding the document data as a dict
176+ mapping document types to URLs or values.
177+
178+ Returns:
179+ A ``Markup`` string of comma-separated links, or ``'No docs'``
180+ if the document data is empty.
181+ """
80182 docs = getattr (model , name )
81183 if not docs :
82184 return 'No docs'
@@ -91,6 +193,14 @@ def docs_link_formatter(model: Any, name: Any) -> Any:
91193
92194
93195class VerificationRequestAdmin (AdminAccessMixin , model = VerificationRequest ):
196+ """
197+ Admin panel view for managing user verification requests.
198+
199+ Allows admins with ``ADMIN`` role to view, approve, or reject user
200+ verification requests. Approving a request automatically upgrades
201+ the user's role to the requested target role.
202+ """
203+
94204 column_list = [
95205 VerificationRequest .id ,
96206 VerificationRequest .user_id ,
@@ -121,6 +231,20 @@ class VerificationRequestAdmin(AdminAccessMixin, model=VerificationRequest):
121231 async def on_model_change (
122232 self , data : dict , model : Any , is_created : bool , request : Request
123233 ) -> None :
234+ """
235+ Handle post-save logic for verification request updates.
236+
237+ When a verification request status is changed to ``APPROVED``, this
238+ hook automatically updates the associated user's role to the
239+ requested target role and marks the user as verified.
240+
241+ Args:
242+ data: Dictionary of form field values being saved.
243+ model: The ``VerificationRequest`` model instance being updated.
244+ is_created: ``True`` if this is a new record creation; ``False``
245+ for updates.
246+ request: The incoming HTTP request.
247+ """
124248 if not is_created and data .get ('status' ) == VerificationStatus .APPROVED :
125249 async with async_session_factory () as session :
126250 result = await session .execute (
@@ -133,6 +257,13 @@ async def on_model_change(
133257
134258
135259class UserAdmin (ModelView , model = User ):
260+ """
261+ Admin panel view for managing user accounts.
262+
263+ Supports both ``ADMIN`` and ``MODERATOR`` roles. Moderators can view
264+ users but cannot create, edit, or delete records.
265+ """
266+
136267 column_list = [User .id , User .email , User .role , User .is_active ]
137268 column_searchable_list = [User .id , User .email ]
138269 can_delete = False
@@ -142,6 +273,20 @@ class UserAdmin(ModelView, model=User):
142273 column_default_sort = [('created_at' , True )]
143274
144275 def is_accessible (self , request : Request ) -> bool :
276+ """
277+ Check whether the requesting user can access this admin view.
278+
279+ Allows both ``ADMIN`` and ``MODERATOR`` roles. Moderators are
280+ restricted from create, edit, and delete operations.
281+
282+ Args:
283+ request: The incoming HTTP request with user information and
284+ route details.
285+
286+ Returns:
287+ ``True`` if the user has an allowed role and the requested
288+ operation is permitted; ``False`` otherwise.
289+ """
145290 user = getattr (request .state , 'user' , None )
146291 if not user :
147292 return False
@@ -163,6 +308,14 @@ def is_accessible(self, request: Request) -> bool:
163308
164309
165310class ProductAdmin (ModelView , model = Product ):
311+ """
312+ Admin panel view for managing product listings.
313+
314+ Allows admins to view product details, update moderation status,
315+ assign moderators, and add moderation comments. Creation and
316+ deletion are disabled.
317+ """
318+
166319 column_list = [
167320 Product .id ,
168321 Product .name ,
@@ -199,6 +352,13 @@ class ProductAdmin(ModelView, model=Product):
199352
200353
201354class OrderAdmin (ModelView , model = Order ):
355+ """
356+ Admin panel view for viewing customer orders.
357+
358+ Provides read-only access to order records with formatted status
359+ badges and user links. Creation, editing, and deletion are disabled.
360+ """
361+
202362 column_list = [
203363 Order .id ,
204364 Order .user_id ,
@@ -220,6 +380,13 @@ class OrderAdmin(ModelView, model=Order):
220380
221381
222382class ReservationAdmin (ModelView , model = Reservation ):
383+ """
384+ Admin panel view for viewing product reservations.
385+
386+ Displays reservation details including product, user, quantity, and
387+ expiration time. All mutations (create, edit, delete) are disabled.
388+ """
389+
223390 column_list = [
224391 Reservation .id ,
225392 Reservation .product_id ,
@@ -246,6 +413,13 @@ class ReservationAdmin(ModelView, model=Reservation):
246413
247414
248415class AuditLogAdmin (AdminAccessMixin , model = AuditLog ):
416+ """
417+ Admin panel view for viewing audit log entries.
418+
419+ Provides read-only access to the audit trail, showing all recorded
420+ actions, target objects, and actors. Restricted to ``ADMIN`` role.
421+ """
422+
249423 column_list = [
250424 AuditLog .id ,
251425 AuditLog .target_type ,
@@ -269,6 +443,13 @@ class AuditLogAdmin(AdminAccessMixin, model=AuditLog):
269443
270444
271445class APIKeyB2BPartnerAdmin (AdminAccessMixin , model = APIKeyB2BPartner ):
446+ """
447+ Admin panel view for managing B2B partner API keys.
448+
449+ Displays API key records with user associations, key names, and
450+ prefixes. Restricted to ``ADMIN`` role. Deletion is disabled.
451+ """
452+
272453 column_list = [
273454 APIKeyB2BPartner .id ,
274455 APIKeyB2BPartner .user_id ,
@@ -289,6 +470,16 @@ class APIKeyB2BPartnerAdmin(AdminAccessMixin, model=APIKeyB2BPartner):
289470
290471
291472def register_admin_views (admin : Any ) -> None :
473+ """
474+ Register all admin model views with the SQLAdmin instance.
475+
476+ Adds each admin view class (users, products, orders, reservations,
477+ audit logs, API keys, and verification requests) to the provided
478+ admin object.
479+
480+ Args:
481+ admin: The SQLAdmin ``Admin`` instance to register views with.
482+ """
292483 admin .add_view (UserAdmin )
293484 admin .add_view (ProductAdmin )
294485 admin .add_view (OrderAdmin )
0 commit comments