Coverage for src / lexigram / admin / resources / users.py: 0%
55 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-13 18:58 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-13 18:58 +0800
1"""
2User resource definition for Lexigram Admin.
4This module defines the UserResource class that provides admin interface
5for managing users with date range filtering capabilities.
6"""
8from __future__ import annotations
10from typing import Any
12from lexigram.admin.resources.base import Resource
13from lexigram.admin.schema import BooleanField, DateField, SelectField, TextField
14from lexigram.admin.ui.filters import SelectFilter, ToggleFilter
15from lexigram.ui import (
16 BadgeColumn,
17 CreateAction,
18 DateColumn,
19 DeleteAction,
20 EditAction,
21 TextColumn,
22)
25class UserResource(Resource):
26 """
27 Admin resource for managing users.
29 Provides comprehensive user management with filtering by registration date
30 and last active date using DateRangeFilter.
31 """
33 # Model configuration
34 model = None # Will be set by DI or registry
35 service = None # Will be set by DI or registry
37 # UI Configuration
38 layout_type = "sidebar"
39 data_view = "tabular"
41 # New SchemaField declarations (canonical definition)
42 fields: list[Any] = [
43 TextField(name="name", sortable=True, searchable=True),
44 TextField(name="email", sortable=True, searchable=True),
45 SelectField(
46 name="role",
47 options=[
48 ("admin", "Admin"),
49 ("moderator", "Moderator"),
50 ("user", "User"),
51 ("guest", "Guest"),
52 ],
53 ),
54 SelectField(
55 name="status",
56 options=[
57 ("active", "Active"),
58 ("inactive", "Inactive"),
59 ("pending", "Pending"),
60 ("suspended", "Suspended"),
61 ],
62 ),
63 DateField(name="created_at", label="Registration Date", sortable=True),
64 DateField(name="last_active", sortable=True),
65 BooleanField(name="is_active", label="Active"),
66 ]
68 # Columns configuration (legacy — kept for backward compat)
69 @property
70 def columns(self) -> list[Any]: # type: ignore[override]
71 """Define the columns for the user table."""
72 return [
73 TextColumn("name").sortable().searchable().weight("semibold"),
74 TextColumn("email").sortable().searchable().copyable().color("blue"),
75 BadgeColumn(
76 "role",
77 colors={
78 "admin": "purple",
79 "moderator": "blue",
80 "user": "gray",
81 "guest": "slate",
82 },
83 ),
84 BadgeColumn(
85 "status",
86 colors={
87 "active": "green",
88 "inactive": "red",
89 "pending": "yellow",
90 "suspended": "orange",
91 },
92 ),
93 DateColumn("created_at").label("Registration Date").datetime().sortable(), # type: ignore[operator]
94 DateColumn("last_active").datetime().sortable(),
95 ToggleFilter("is_active", label="Active"),
96 ]
98 # Filter configuration
99 @property
100 def filter_options(self) -> dict[str, Any]:
101 """Define filter options for the user resource."""
102 field_map: dict[str, Any] = {f.name: f for f in self.fields}
103 return {
104 "role": SelectFilter(
105 "role",
106 options=[v for v, _ in field_map["role"].options],
107 label="Role",
108 ),
109 "status": SelectFilter(
110 "status",
111 options=[v for v, _ in field_map["status"].options],
112 label="Status",
113 ),
114 "is_active": ToggleFilter("is_active", label="Active"),
115 }
117 # Actions configuration
118 @property
119 def actions(self) -> list[Any]: # type: ignore[override]
120 """Define row-level actions."""
121 return [
122 EditAction(),
123 DeleteAction(),
124 ]
126 # Header actions
127 @property
128 def header_actions(self) -> list[Any]:
129 """Define header-level actions."""
130 return [
131 CreateAction(label="Add User"),
132 ]
134 # Search configuration
135 search_fields = ["name", "email"]
137 # Bulk actions
138 bulk_actions: list[Any] = ["delete_selected", "export_csv"]
140 # Permissions
141 def has_view_permission(self, user: Any) -> bool:
142 """Check if user can view users."""
143 return user and (user.is_admin or user.role in ["admin", "moderator"])
145 def has_add_permission(self, user: Any) -> bool:
146 """Check if user can add users."""
147 return user and user.is_admin
149 def has_change_permission(self, user: Any) -> bool:
150 """Check if user can change users."""
151 return user and (user.is_admin or user.role in ["admin", "moderator"])
153 def has_delete_permission(self, user: Any) -> bool:
154 """Check if user can delete users."""
155 return user and user.is_admin
157 # Custom methods
158 async def get_queryset(self, request: Any) -> Any:
159 """Get the base queryset for users."""
160 if self.service:
161 return await self.service.list()
162 return []
164 async def get_object(self, pk: Any) -> Any:
165 """Get a single user object."""
166 if self.service:
167 return await self.service.get_by_id(pk)
168 return None
170 async def create_object(self, data: dict[str, Any]) -> Any:
171 """Create a new user."""
172 if self.service:
173 return await self.service.create(data)
174 return None
176 async def update_object(self, pk: Any, data: dict[str, Any]) -> Any:
177 """Update an existing user."""
178 if self.service:
179 return await self.service.update(pk, data)
180 return None
182 async def delete_object(self, pk: Any) -> bool:
183 """Delete a user."""
184 if self.service:
185 return await self.service.delete(pk)
186 return False