123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189openLwt.SyntaxmoduleCore=Sihl_coremoduleUser=Modelletlog_src=Logs.Src.create"sihl.service.user"moduleLogs=(valLogs.src_loglog_src:Logs.LOG)exceptionExceptionofstringmoduleMake(Repo:Sig.REPOSITORY):Sig.SERVICE=structletfind_opt~user_id=Repo.get~id:user_idletfind~user_id=let*m_user=find_opt~user_idinmatchm_userwith|Someuser->Lwt.returnuser|None->Logs.err(funm->m"USER: User not found with id %s"user_id);raise(Exception"User not found");;letfind_by_email_opt~email=(* TODO add support for lowercase UTF-8
* String.lowercase only supports US-ASCII, but
* email addresses can contain other letters
* (https://tools.ietf.org/html/rfc6531) like umlauts.
*)Repo.get_by_email~email:(String.lowercase_asciiemail);;letfind_by_email~email=let*user=find_by_email_opt~emailinmatchuserwith|Someuser->Lwt.returnuser|None->Logs.err(funm->m"USER: User not found with email %s"email);raise(Exception"User not found");;letfind_all~query=Repo.get_all~queryletupdate_password?(password_policy=User.default_password_policy)~user~old_password~new_password~new_password_confirmation()=matchUser.validate_change_passworduser~old_password~new_password~new_password_confirmation~password_policywith|Ok()->letupdated_user=matchUser.set_user_passwordusernew_passwordwith|Okuser->user|Errormsg->Logs.err(funm->m"USER: Can not update password of user %s: %s"(User.emailuser)msg);raise(Exceptionmsg)inlet*()=Repo.update~user:updated_userinLwt.return@@Okupdated_user|Errormsg->Lwt.return@@Errormsg;;letupdate_details~user~email~username=letupdated_user=User.set_user_detailsuser~email~usernameinlet*()=Repo.update~user:updated_userinfind~user_id:(User.iduser);;letset_password?(password_policy=User.default_password_policy)~user~password~password_confirmation()=let*result=User.validate_new_password~password~password_confirmation~password_policy|>Lwt.returninmatchresultwith|Errormsg->Lwt.return@@Errormsg|Ok()->letupdated_user=matchUser.set_user_passworduserpasswordwith|Okuser->user|Errormsg->Logs.err(funm->m"USER: Can not set password of user %s: %s"(User.emailuser)msg);raise(Exceptionmsg)inlet*()=Repo.update~user:updated_userinLwt_result.returnupdated_user;;letcreate_user~email~password~username=letuser=matchUser.create~email~password~username~admin:false~confirmed:falsewith|Okuser->user|Errormsg->raise(Exceptionmsg)inlet*()=Repo.insert~userinLwt.returnuser;;letcreate_admin~email~password~username=let*user=Repo.get_by_email~emailinlet*()=matchuserwith|Some_->Logs.err(funm->m"USER: Can not create admin %s since the email is already taken"email);raise(Exception"Email already taken")|None->Lwt.return()inletuser=matchUser.create~email~password~username~admin:true~confirmed:truewith|Okuser->user|Errormsg->Logs.err(funm->m"USER: Can not create admin %s %s"emailmsg);raise(Exceptionmsg)inlet*()=Repo.insert~userinLwt.returnuser;;letregister_user?(password_policy=User.default_password_policy)?username~email~password~password_confirmation()=matchUser.validate_new_password~password~password_confirmation~password_policywith|Errormsg->Lwt_result.fail@@Model.Error.InvalidPasswordProvidedmsg|Ok()->let*user=find_by_email_opt~emailin(matchuserwith|None->create_user~username~email~password|>Lwt.mapResult.ok|Some_->Lwt_result.failModel.Error.AlreadyRegistered);;letlogin~email~password=let*user=find_by_email_opt~emailinmatchuserwith|None->Lwt_result.failModel.Error.DoesNotExist|Someuser->ifUser.matches_passwordpassworduserthenLwt_result.returnuserelseLwt_result.failModel.Error.IncorrectPassword;;letcreate_admin_cmd=Core.Command.make~name:"createadmin"~help:"<username> <email> <password>"~description:"Create an admin user"(funargs->matchargswith|[username;email;password]->create_admin~email~password~username:(Someusername)|>Lwt.mapignore|_->raise(Core.Command.Exception"Usage: <username> <email> <password>"));;letstart()=Lwt.return()letstop()=Lwt.return()letlifecycle=Core.Container.Lifecycle.create"user"~dependencies:Repo.lifecycles~start~stop;;letregister()=Repo.register_migration();Repo.register_cleaner();Core.Container.Service.create~commands:[create_admin_cmd]lifecycle;;end