1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
//! Superuser creation support for management commands.
//!
//! Provides type-erased superuser creation that works with any user model.
//!
//! # Architecture
//!
//! The [`SuperuserInit`] trait is automatically implemented by the `#[user]`
//! macro, providing compile-time field name resolution. This ensures correct
//! behavior even when fields are renamed via `#[user_field(...)]` (e.g.,
//! `date_joined` mapped to `created_at`).
//!
//! The [`SuperuserCreator`] trait provides the async database persistence
//! layer, and [`TypedSuperuserCreator<U>`] bridges the two by combining
//! [`SuperuserInit`] for construction with `Model` for ORM operations.
//!
//! # Registration
//!
//! When `#[user]` and `#[model]` are both applied to a struct, the framework
//! automatically registers a [`SuperuserCreator`] via the `inventory` crate.
//! No manual registration is needed. This works for both full user models
//! (with `full = true`) and minimal user models — fields that are absent
//! from the user struct (e.g., `email`, `is_staff`, `date_joined`) are
//! simply skipped when constructing the superuser.
//!
//! For advanced use cases (e.g., custom creator logic), manual registration
//! is still supported and takes priority over auto-registration:
//!
//! ## Recommended: Using `#[user]` macro
//!
//! The simplest path is to use `#[user(...)]` with `#[model]`, which
//! auto-generates [`SuperuserInit`]:
//!
//! ```rust,ignore
//! use reinhardt_auth::{register_superuser_creator, superuser_creator_for};
//! use myapp::models::CustomUser;
//!
//! // CustomUser has #[user(hasher = Argon2Hasher, username_field = "username")]
//! // and #[model(table_name = "auth_user")] — SuperuserInit is auto-generated.
//! register_superuser_creator(superuser_creator_for::<CustomUser>());
//! ```
//!
//! ## Manual `BaseUser` implementors
//!
//! If you implement [`BaseUser`] manually without the `#[user]` macro,
//! you can still use `createsuperuser` by implementing [`SuperuserInit`]
//! yourself. See the [`SuperuserInit`] documentation for an example.
use async_trait;
use PhantomData;
use OnceLock;
use crateBaseUser;
/// Trait for initializing a user struct as a superuser.
///
/// # Auto-generation (recommended)
///
/// This trait is automatically implemented by the `#[user]` attribute macro
/// when `#[model]` is also present, regardless of whether `full = true` is
/// set. Setters for optional fields (`email`, `is_staff`, `date_joined`,
/// etc.) are emitted as no-ops when the field is absent, so minimal user
/// structs are supported. The macro uses compile-time field name resolution,
/// so field renames via `#[user_field(...)]` are handled correctly.
///
/// # Manual implementation
///
/// Projects that implement [`BaseUser`] manually (without the `#[user]`
/// macro) can implement this trait directly. The struct must also
/// implement `Default`.
///
/// ```rust,ignore
/// use reinhardt_auth::SuperuserInit;
///
/// impl SuperuserInit for MyUser {
/// fn init_superuser(username: &str, email: &str) -> Self {
/// Self {
/// username: username.to_string(),
/// email: email.to_string(),
/// is_superuser: true,
/// is_staff: true,
/// is_active: true,
/// date_joined: chrono::Utc::now(),
/// ..Default::default()
/// }
/// }
/// }
/// ```
///
/// Then register in `manage.rs`:
///
/// ```rust,ignore
/// register_superuser_creator(superuser_creator_for::<MyUser>());
/// ```
/// Type-erased superuser creation interface.
///
/// Implementations handle both user construction and database persistence.
/// Generic [`SuperuserCreator`] for any user type with `#[user]` + `#[model]`.
///
/// `U` must implement:
/// - [`SuperuserInit`] (generated by `#[user]` macro)
/// - [`BaseUser`] (generated by `#[user]` macro — provides `set_password`)
/// - [`Model`](reinhardt_db::prelude::Model) (generated by `#[model]` macro — provides `objects().create()`)
/// Create a [`SuperuserCreator`] for a specific user type.
///
/// The user type must have `#[user(...)]` and `#[model(...)]` macros applied.
///
/// # Example
///
/// ```rust,ignore
/// use reinhardt_auth::superuser_creator_for;
/// use myapp::models::CustomUser;
///
/// let creator = superuser_creator_for::<CustomUser>();
/// ```
/// Global registry for the superuser creator.
static SUPERUSER_CREATOR: = new;
/// Register a [`SuperuserCreator`] for use by the `createsuperuser` command.
///
/// This should be called early in program startup (e.g., in `main()`)
/// before `execute_from_command_line`.
///
/// # Panics
///
/// Panics if called more than once.
/// Retrieve the registered [`SuperuserCreator`].
///
/// Returns `None` if [`register_superuser_creator`] has not been called
/// and no auto-registration was found.
// ============================================================================
// Auto-registration via inventory
// ============================================================================
/// Compile-time registration entry for auto-discovered superuser creators.
///
/// Submitted via `inventory::submit!` by the `#[user]` macro whenever
/// `#[model]` is also present. The framework collects all submissions at
/// startup and populates the global [`OnceLock`]. `full = true` is not
/// required.
///
/// You typically do not create this struct directly — the `#[user]` macro
/// generates the registration code automatically.
collect!;
/// Auto-register a [`SuperuserCreator`] from inventory submissions.
///
/// Called by the framework before command dispatch. If a creator was already
/// registered manually via [`register_superuser_creator`], this is a no-op
/// (preserving backwards compatibility) regardless of how many `#[user]` +
/// `#[model]` types exist in the inventory.
///
/// # Panics
///
/// Panics if multiple `#[user]` + `#[model]` types are found in the
/// inventory and no manual registration has been made. Only one user model
/// can serve as the auto-registered superuser creator; if you legitimately
/// have multiple user models, opt out by calling
/// [`register_superuser_creator`] manually before command dispatch.