github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/server/inscriptions/views.go (about) 1 package inscriptions 2 3 import ( 4 "fmt" 5 "net/http" 6 "strconv" 7 8 rd "github.com/benoitkugler/goACVE/server/core/rawdata" 9 10 "github.com/benoitkugler/goACVE/server/core/utils/mails" 11 12 "github.com/benoitkugler/goACVE/server/shared" 13 "github.com/labstack/echo" 14 ) 15 16 const ( 17 UrlInscriptions = "/inscription" 18 EndPointValidMail = "/valide-mail" 19 ) 20 21 func isSimpleSejour(idS string, campsSimple map[int64]CampSimple) (out CampSimple, ok bool) { 22 id, err := strconv.ParseInt(idS, 10, 64) 23 if err != nil { 24 return out, false // par défaut on renvoie sur la page classique. 25 } 26 out, ok = campsSimple[id] 27 return 28 } 29 30 // FormulaireInscription affiche la page d'inscription, 31 // qui dépend du camp éventuellement présent dans l'url. 32 func (ct Controller) FormulaireInscription(c echo.Context) error { 33 data, err := ct.loadCamps() 34 _, campsSimple := data.triCamps() 35 if err != nil { 36 return shared.RedirectError(c, shared.FormatErr("La liste des camps n'a pu être résolue.", err)) 37 } 38 39 // Formulaire complet par défaut 40 // les données nécessaires sont chargées par 41 // une requête client, gérée par `HandleLoadDataInscriptions` 42 meta := MetaInscription{IsComplet: true} 43 44 preselectedId := c.Param("preselected") 45 if campSimple, ok := isSimpleSejour(preselectedId, campsSimple); ok { 46 // Formulaire simplifié 47 meta = MetaInscription{IsComplet: false, LabelCampSimple: campSimple.Label.String()} 48 } 49 return shared.HtmlWithPayload(c, "server/static/bv/inscription.html", meta) 50 } 51 52 // HandleLoadDataInscriptions décode la préinscription et renvoie les 53 // données des séjours. 54 func (ct Controller) HandleLoadDataInscriptions(c echo.Context) error { 55 data, err := ct.loadCamps() 56 camps, _ := data.triCamps() 57 if err != nil { 58 return fmt.Errorf("La liste des camps n'a pu être résolue. <br/>Détails : <i>%s</i>", err) 59 } 60 preselectedId := c.QueryParam("preselected") 61 62 var initialInscription rd.Inscription 63 crypted := c.QueryParam("preinscription") 64 if crypted != "" { 65 initialInscription, err = ct.decodePreinscription(crypted) 66 if err != nil { 67 return err 68 } 69 } 70 71 initialInscription.PartageAdressesOK = true // OK par défaut 72 73 out := DataInscription{ 74 Camps: camps, 75 PreselectCamp: preselectedId, 76 InitialInscription: initialInscription, 77 } 78 return c.JSON(200, out) 79 } 80 81 // CheckMail analyse l'adresse mail donnée et envoie 82 // un lien d'inscription rapide aux personnes concernées. 83 func (ct Controller) CheckMail(c echo.Context) error { 84 type out struct { 85 MailFound bool `json:"mail_found"` 86 } 87 88 mail := c.QueryParam("mail") 89 candidats, err := ct.chercheMail(mail) 90 if err != nil { 91 return err 92 } 93 if mailFound := len(candidats.responsables) > 0; !mailFound { 94 return c.JSON(200, out{MailFound: false}) 95 } 96 97 targets, err := ct.buildLiensPreinscription(candidats, c.QueryParam("origin")) 98 if err != nil { 99 return err 100 } 101 102 html, err := mails.NewPreinscription(mail, targets) 103 if err != nil { 104 return err 105 } 106 if err = mails.NewMailer(ct.SMTP).SendMail(mail, "[ACVE] Inscription rapide", html, nil, nil); err != nil { 107 return err 108 } 109 110 return c.JSON(200, out{MailFound: true}) 111 } 112 113 // EnregistreInscriptionComplete vérifie l'inscription 114 // et valide le mail (soit directement, soit par lien de confirmation) 115 func (ct Controller) EnregistreInscriptionComplete(c echo.Context) error { 116 facture, responsable, mailValidated, err := ct.enregistreInscriptionComplete(c) 117 if err != nil { 118 return err 119 } 120 121 var out EnregistreInscriptionOut 122 out.CheckMail = !mailValidated 123 if mailValidated { 124 out.UrlEspacePerso = getUrlEspacePerso(facture, c.Request()) 125 } else { 126 err = ct.verifieMail(c.Request().Host, facture, responsable) 127 if err != nil { 128 return err 129 } 130 } 131 132 return c.JSON(200, out) 133 } 134 135 // RejoueInscriptionComplete enregristre l'inscription mais ne vérifie pas le mail 136 // Entre autre, aucun mail n'est envoyé. 137 func (ct Controller) RejoueInscriptionComplete(c echo.Context) error { 138 _, _, _, err := ct.enregistreInscriptionComplete(c) 139 if err != nil { 140 return err 141 } 142 return c.JSON(200, "OK") // le client attend un corps JSON 143 } 144 145 func (ct Controller) enregistreInscriptionComplete(c echo.Context) (rd.Facture, rd.Personne, bool, error) { 146 var insc rd.Inscription 147 if err := c.Bind(&insc); err != nil { 148 return rd.Facture{}, rd.Personne{}, false, shared.FormatErr("Les paramètres d'inscriptions ne semblent pas valides.", err) 149 } 150 151 if err := valideInscription(insc); err != nil { 152 return rd.Facture{}, rd.Personne{}, false, err 153 } 154 155 if err := ct.decodeLienId(&insc.Responsable.Lienid); err != nil { 156 return rd.Facture{}, rd.Personne{}, false, shared.FormatErr("Le cryptage de la pré-identification du responsable semble incorrect !", err) 157 } 158 159 data, err := ct.loadCamps() 160 if err != nil { 161 return rd.Facture{}, rd.Personne{}, false, shared.FormatErr("La liste des camps ouverts aux inscriptions n'a pu être consultée.", err) 162 } 163 for index, part := range insc.Participants { 164 if _, in := data.camps[part.IdCamp]; !in { 165 return rd.Facture{}, rd.Personne{}, false, fmt.Errorf("Le camp numéro %d n'est pas ouvert aux inscriptions !", part.IdCamp) 166 } 167 if err := ct.decodeLienId(&insc.Participants[index].Lienid); err != nil { 168 return rd.Facture{}, rd.Personne{}, false, shared.FormatErr("Le cryptage de la pré-identification d'un participant semble incorrect !", err) 169 } 170 } 171 172 mailValidated := false 173 // on saute l'envoi d'un mail de vérification uniquement 174 // pour les responsables pré-identifié dont l'adresse n'a pas changé 175 if insc.Responsable.Lienid.Valid { 176 hasChanged, err := ct.hasMailChanged(insc.Responsable.Mail, insc.Responsable.Lienid) 177 if err != nil { 178 return rd.Facture{}, rd.Personne{}, false, err 179 } 180 mailValidated = !hasChanged 181 } 182 183 // on enregistre dans tous les cas l'inscription 184 facture, responsable, err := ct.enregistreInscription(insc, mailValidated, data) 185 return facture, responsable, mailValidated, err 186 } 187 188 func getUrlEspacePerso(facture rd.Facture, req *http.Request) string { 189 endpoint := facture.UrlEspacePerso("espace_perso/") 190 return shared.BuildUrl(req.Host, endpoint, map[string]string{"show-hint": "ok"}) 191 } 192 193 // ValideMail décrypte l'id de la facture et 194 // renvoie vers l'espace perso 195 func (ct Controller) ValideMail(c echo.Context) error { 196 facture, err := ct.confirmeInscription(c.QueryParam("crypted-id")) 197 if err != nil { 198 return shared.RedirectError(c, err) 199 } 200 return c.Redirect(307, getUrlEspacePerso(facture, c.Request())) 201 } 202 203 // --------------- Formulaire simplifié ------------------------------------- 204 205 // EnregistreInscriptionSimple enregistre une inscription sur un séjour simplifié. 206 func (ct Controller) EnregistreInscriptionSimple(c echo.Context) error { 207 var insc InscriptionSimple 208 if err := c.Bind(&insc); err != nil { 209 return shared.FormatErr("Les paramètres d'inscriptions ne semblent pas valides !", err) 210 } 211 212 data, err := ct.loadCamps() 213 _, campsSimple := data.triCamps() 214 if err != nil { 215 return shared.FormatErr("La liste des camps n'a pu être résolue.", err) 216 } 217 218 preselectedId := c.QueryParam("preselected") 219 campSimple, ok := isSimpleSejour(preselectedId, campsSimple) 220 if !ok { 221 return fmt.Errorf("Le séjour demandé ne propose pas d'inscription simplifiée.") 222 } 223 224 err = ct.enregistreInscriptionSimple(insc, campSimple) 225 if err != nil { 226 return err 227 } 228 return c.NoContent(200) 229 }