module Form = Dream_html.Form type fields = | Single of { load : float; reps : int; extension : Evidence.Stimulus.extension option; } | Pair of { iso_load : float; iso_reps : int; comp_load : float; comp_reps : int; extension : Evidence.Stimulus.extension option; } let extension = function | "" -> Ok None | "forced" -> Ok (Some Evidence.Stimulus.Forced_reps) | "negatives" -> Ok (Some Evidence.Stimulus.Negatives) | "rest-pause" -> Ok (Some Evidence.Stimulus.Rest_pause) | "static" -> Ok (Some Evidence.Stimulus.Static_hold) | _ -> Error "error.extension" let load value = match Form.float ~min:0. value with | Ok value -> Ok value | Error "error.expected.int" -> Error "error.expected.number" | Error _ -> Error "error.load" let reps value = match Form.int value with | Error error -> Error error | Ok value when value > 0 -> Ok value | Ok _ -> Error "error.reps" let fields prescription = let open Form in match Prescription.Stimulus.delivery prescription with | Prescription.Stimulus.Single _ -> let+ load = required load "load" and+ reps = required reps "reps" and+ extension = required extension "extension" in Single { load; reps; extension } | Prescription.Stimulus.Pre_exhaust _ -> let+ iso_load = required load "iso_load" and+ iso_reps = required reps "iso_reps" and+ comp_load = required load "comp_load" and+ comp_reps = required reps "comp_reps" and+ extension = required extension "extension" in Pair { iso_load; iso_reps; comp_load; comp_reps; extension } let stimulus prescription = let open Form in let* values = fields prescription in match (Prescription.Stimulus.delivery prescription, values) with | Prescription.Stimulus.Single exercise, Single { load; reps; extension } -> let outcome = match extension with | None -> Evidence.Stimulus.Positive_failure | Some extension -> Evidence.Stimulus.Beyond_failure (extension, []) in ok (Evidence.Stimulus.make (Evidence.Stimulus.Single (Evidence.Stimulus.Effort.make ~exercise ~load ~reps ~outcome))) | ( Prescription.Stimulus.Pre_exhaust { isolation; compound }, Pair { iso_load; iso_reps; comp_load; comp_reps; extension } ) -> let second_outcome = match extension with | None -> Evidence.Stimulus.Positive_failure | Some extension -> Evidence.Stimulus.Beyond_failure (extension, []) in let first = Evidence.Stimulus.Effort.make ~exercise:isolation ~load:iso_load ~reps:iso_reps ~outcome:Evidence.Stimulus.Positive_failure in let second = Evidence.Stimulus.Effort.make ~exercise:compound ~load:comp_load ~reps:comp_reps ~outcome:second_outcome in ok (Evidence.Stimulus.make (Evidence.Stimulus.Pair { first; second })) | _ -> assert false let override = Form.required Form.bool "override" (* --- profile --- *) (* The raw username string; the domain normalizes and validates it downstream. *) let profile_username = Form.required Form.string "username" (* Current and new password, both required. Passwords carry no policy here; the service verifies the current one before storing the new one. *) let profile_password = let open Form in let+ current = required string "current" and+ next = required string "next" in (current, next) (* --- application feedback --- *) let app_feedback = Form.required Form.string "message" (* --- error presentation --- *) let message = function | "error.required" -> "Enter a value." | "error.expected.number" -> "Enter a valid number." | "error.expected.int" -> "Enter a valid whole number." | "error.reps" -> "Enter at least one repetition." | "error.load" -> "Enter a finite, nonnegative load." | "error.extension" -> "Select one of the offered endings." | key -> key let errors_to_text errors = errors |> List.map (fun (_, key) -> message key) |> String.concat " "