summaryrefslogtreecommitdiff
path: root/src/user/snapshot.rs
diff options
context:
space:
mode:
authorOwen Jacobson <owen@grimoire.ca>2025-03-23 15:58:33 -0400
committerOwen Jacobson <owen@grimoire.ca>2025-03-23 16:25:22 -0400
commit2420f1e75d54a5f209b0267715f078a369d81eb1 (patch)
tree20edd531a3f2f765a23fef8e7a508c91bc7dc294 /src/user/snapshot.rs
parent7e15690d54ff849596401b43d163df9353062850 (diff)
Rename the `login` module to `user`.
Diffstat (limited to 'src/user/snapshot.rs')
-rw-r--r--src/user/snapshot.rs52
1 files changed, 52 insertions, 0 deletions
diff --git a/src/user/snapshot.rs b/src/user/snapshot.rs
new file mode 100644
index 0000000..d548e06
--- /dev/null
+++ b/src/user/snapshot.rs
@@ -0,0 +1,52 @@
+use super::{
+ Id,
+ event::{Created, Event},
+};
+use crate::name::Name;
+
+// This also implements FromRequestParts (see `./extract.rs`). As a result, it
+// can be used as an extractor for endpoints that want to require a user, or for
+// endpoints that need to behave differently depending on whether the client is
+// or is not logged in.
+#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
+pub struct User {
+ pub id: Id,
+ pub name: Name,
+ // The omission of the hashed password is deliberate, to minimize the
+ // chance that it ends up tangled up in debug output or in some other chunk
+ // of logic elsewhere.
+}
+
+impl User {
+ // Without this allow, clippy wants the `Option<Self>` return type to be `Self`. It's not a bad
+ // suggestion, but we need `Option` here, for two reasons:
+ //
+ // 1. This is used to collect streams using a fold, below, which requires a type
+ // consistent with the fold, and
+ // 2. It's also consistent with the other history state machine types.
+ #[allow(clippy::unnecessary_wraps)]
+ fn apply(state: Option<Self>, event: Event) -> Option<Self> {
+ match (state, event) {
+ (None, Event::Created(event)) => Some(event.into()),
+ (state, event) => panic!("invalid message event {event:#?} for state {state:#?}"),
+ }
+ }
+}
+
+impl FromIterator<Event> for Option<User> {
+ fn from_iter<I: IntoIterator<Item = Event>>(events: I) -> Self {
+ events.into_iter().fold(None, User::apply)
+ }
+}
+
+impl From<&Created> for User {
+ fn from(event: &Created) -> Self {
+ event.user.clone()
+ }
+}
+
+impl From<Created> for User {
+ fn from(event: Created) -> Self {
+ event.user
+ }
+}