Header menu logo FCQRS

Modifications to User Aggregate

We have to modify the user aggregate such that instead of register succeeded event, we will issue a verification requested event which in turn will start a saga. Relevant changes are below

type Event =
    | LoginSucceeded
    | LoginFailed
    | AlreadyRegistered
    | VerificationRequested of string * string  * string
    | Verified

type Command =
    | Login of string
    | Verify of string
    | Register of string * string

type State =
    { Username: string option
      VerificationCode: string option
      Password: string option }

let applyEvent event state =
    match event.EventDetails with
    | VerificationRequested(userName, password, code) ->
        { state with
            VerificationCode= Some code
            Username = Some userName
            Password = Some password }
    | _ -> state

let handleCommand (cmd: Command<_>) state =
    match cmd.CommandDetails, state with
    | Register(userName, password), { Username = None } -> 
        VerificationRequested(userName, password, 
            Random.Shared.Next(1_000_000).ToString()) |> PersistEvent

    | Register _, { Username = Some _ } -> AlreadyRegistered |> DeferEvent
    | Verify code, { VerificationCode = Some vcode } when code = vcode -> 
        Verified |> PersistEvent
    | Login password1,
      { Username = Some _
        Password = Some password2 } when password1 = password2 -> 
            LoginSucceeded |> PersistEvent
    | Verify _,  _ 
    | Login _, _ -> LoginFailed |> DeferEvent
namespace System
namespace System.IO
namespace Microsoft
namespace Microsoft.Extensions
namespace Microsoft.Extensions.Configuration
namespace Hocon
namespace Hocon.Extensions
namespace Hocon.Extensions.Configuration
namespace FCQRS
module Common from FCQRS
<summary> Contains common types like Events and Commands </summary>
<namespacedoc><summary>Functionality for Write Side.</summary></namespacedoc>
Multiple items
module Event from Microsoft.FSharp.Control

--------------------
type Event = | LoginSucceeded | LoginFailed | AlreadyRegistered | VerificationRequested of string * string * string | Verified

--------------------
type Event<'EventDetails> = { EventDetails: 'EventDetails CreationDate: DateTime Id: MessageId option Sender: ActorId option CorrelationId: CID Version: Version } interface IMessageWithCID interface ISerializable member Equals: Event<'EventDetails> * IEqualityComparer -> bool override ToString: unit -> string
<summary> Represents an event generated by an aggregate actor as a result of processing a command. &lt;typeparam name="'EventDetails"&gt;The specific type of the event payload.&lt;/typeparam&gt; </summary>

--------------------
type Event<'Delegate,'Args (requires delegate and 'Delegate :> Delegate and reference type)> = new: unit -> Event<'Delegate,'Args> member Trigger: sender: obj * args: 'Args -> unit member Publish: IEvent<'Delegate,'Args>

--------------------
new: unit -> Event<'Delegate,'Args>
Multiple items
val string: value: 'T -> string

--------------------
type string = String
Multiple items
module Command

--------------------
type Command = | Login of string | Verify of string | Register of string * string

--------------------
type Command<'CommandDetails> = { CommandDetails: 'CommandDetails CreationDate: DateTime Id: MessageId option Sender: ActorId option CorrelationId: CID } interface IMessageWithCID interface ISerializable member Equals: Command<'CommandDetails> * IEqualityComparer -> bool override ToString: unit -> string
<summary> Represents a command to be processed by an aggregate actor. &lt;typeparam name="'CommandDetails"&gt;The specific type of the command payload.&lt;/typeparam&gt; </summary>

--------------------
type Command<'Command,'Event> = | Execute of CommandDetails<'Command,'Event>
<summary> Represents the message sent to the internal subscription mechanism. &lt;typeparam name="'Command"&gt;The type of the command payload.&lt;/typeparam&gt; &lt;typeparam name="'Event"&gt;The type of the expected event payload.&lt;/typeparam&gt; </summary>
Multiple items
type State = { Username: string option VerificationCode: string option Password: string option }

--------------------
type State<'Command,'Event> = { CommandDetails: CommandDetails<'Command,'Event> Sender: IActorRef }
type 'T option = Option<'T>
val applyEvent: event: Event<Event> -> state: State -> State
val event: Event<Event>
val state: State
Event.EventDetails: Event
<summary> The specific details or payload of the event. </summary>
union case Event.VerificationRequested: string * string * string -> Event
val userName: string
val password: string
val code: string
union case Option.Some: Value: 'T -> Option<'T>
val handleCommand: cmd: Command<Command> -> state: State -> EventAction<Event>
val cmd: Command<Command>
Command.CommandDetails: Command
<summary> The specific details or payload of the command. </summary>
union case Command.Register: string * string -> Command
union case Option.None: Option<'T>
Multiple items
type Random = new: unit -> unit + 1 overload member GetItems<'T> : choices: ReadOnlySpan<'T> * length: int -> 'T array + 2 overloads member Next: unit -> int + 2 overloads member NextBytes: buffer: byte array -> unit + 1 overload member NextDouble: unit -> float member NextInt64: unit -> int64 + 2 overloads member NextSingle: unit -> float32 member Shuffle<'T> : values: Span<'T> -> unit + 1 overload static member Shared: Random
<summary>Represents a pseudo-random number generator, which is an algorithm that produces a sequence of numbers that meet certain statistical requirements for randomness.</summary>

--------------------
Random() : Random
Random(Seed: int) : Random
property Random.Shared: Random with get
<summary>Provides a thread-safe <see cref="T:System.Random" /> instance that may be used concurrently from any thread.</summary>
<returns>A <see cref="T:System.Random" /> instance.</returns>
Random.Next() : int
Random.Next(maxValue: int) : int
Random.Next(minValue: int, maxValue: int) : int
union case EventAction.PersistEvent: 'T -> EventAction<'T>
<summary> Persist the event to the journal. The actor's state will be updated using the event handler *after* persistence succeeds. </summary>
union case Event.AlreadyRegistered: Event
union case EventAction.DeferEvent: 'T -> EventAction<'T>
<summary> Defer the event. It will be stashed and processed later, potentially after other events. </summary>
union case Command.Verify: string -> Command
val vcode: string
union case Event.Verified: Event
union case Command.Login: string -> Command
val password1: string
val password2: string
union case Event.LoginSucceeded: Event
union case Event.LoginFailed: Event

Type something to start searching.