objective categorical abstract machine language personal data server
65
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add account switch endpoint for account switcher

futurGH dd16c861 8059388c

+61 -1
+1
bin/main.ml
··· 40 40 ; ( get 41 41 , "/account/signup/check-handle" 42 42 , Api.Account_.Signup.check_handle_handler ) 43 + ; (post, "/account/switch", Api.Account_.Login.switch_account_handler) 43 44 ; (get, "/account/logout", Api.Account_.Logout.handler) 44 45 ; (* admin ui *) 45 46 (get, "/admin", Api.Admin_.Index.handler)
+27 -1
frontend/src/components/AccountSwitcher.mlx
··· 24 24 25 25 let[@react.component] make ~current_user ~logged_in_users ~add_account_url 26 26 ?(name = "did") ?(inline = false) ?onChange () = 27 + let handleAccountSwitch = 28 + [%browser_only 29 + fun newDid -> 30 + if newDid <> current_user.did then 31 + let formData = Fetch.FormData.make () in 32 + Fetch.FormData.set "did" newDid formData ; 33 + let _ = 34 + Fetch.fetchWithInit "/account/switch" 35 + (Fetch.RequestInit.make ~method_:Fetch.Post 36 + ~body:(Fetch.BodyInit.makeWithFormData formData) 37 + () ) 38 + |> Js.Promise.then_ (fun response -> 39 + if Fetch.Response.ok response then ( 40 + ignore ([%mel.raw {| window.location.reload() |}] : unit) ; 41 + Js.Promise.resolve () ) 42 + else Js.Promise.resolve () ) 43 + |> Js.Promise.catch (fun _ -> Js.Promise.resolve ()) 44 + in 45 + () ; 46 + ( match onChange with 47 + | Some f -> 48 + f newDid 49 + | None -> 50 + () ) 51 + else ()] 52 + in 27 53 let button_class = 28 54 if inline then 29 55 "group inline-flex flex-row items-center px-1.5 py-1 -mx-0.75 -my-1 \ ··· 41 67 <ClientOnly fallback=(fallback current_user.handle current_user.avatar_data_uri)> 42 68 [%browser_only 43 69 (fun () -> 44 - <Aria.Select name className="inline" defaultValue=current_user.did placeholder="select account" ?onChange> 70 + <Aria.Select name className="inline" defaultValue=current_user.did placeholder="select account" onChange=handleAccountSwitch> 45 71 <Aria.Button className=button_class> 46 72 <Aria.SelectValue className=value_class /> 47 73 </Aria.Button>
+33
pegasus/lib/api/account_/login.ml
··· 11 11 (module Frontend.LoginPage) 12 12 ~props:{redirect_url; csrf_token; error= None} ) 13 13 14 + type switch_account_response = 15 + {success: bool; error: string option [@default None]} 16 + [@@deriving yojson {strict= false}] 17 + 18 + let switch_account_handler = 19 + Xrpc.handler (fun ctx -> 20 + match%lwt Dream.form ctx.req with 21 + | `Ok fields -> ( 22 + let did = List.assoc_opt "did" fields in 23 + match did with 24 + | Some did -> 25 + let%lwt logged_in_dids = Session.Raw.get_logged_in_dids ctx.req in 26 + if List.mem did logged_in_dids then 27 + let%lwt () = Session.Raw.set_current_did ctx.req did in 28 + Dream.json @@ Yojson.Safe.to_string 29 + @@ switch_account_response_to_yojson {success= true; error= None} 30 + else 31 + Dream.json ~status:`Bad_Request 32 + @@ Yojson.Safe.to_string 33 + @@ switch_account_response_to_yojson 34 + { success= false 35 + ; error= Some "not logged in as this account" } 36 + | None -> 37 + Dream.json ~status:`Bad_Request 38 + @@ Yojson.Safe.to_string 39 + @@ switch_account_response_to_yojson 40 + {success= false; error= Some "missing did parameter"} ) 41 + | _ -> 42 + Dream.json ~status:`Bad_Request 43 + @@ Yojson.Safe.to_string 44 + @@ switch_account_response_to_yojson 45 + {success= false; error= Some "invalid form submission"} ) 46 + 14 47 let post_handler = 15 48 Xrpc.handler (fun ctx -> 16 49 let csrf_token = Dream.csrf_token ctx.req in