github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/server/acvegestion/views.go (about) 1 package acvegestion 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "mime" 8 "strconv" 9 "time" 10 11 "github.com/benoitkugler/goACVE/server/documents" 12 "github.com/benoitkugler/goACVE/server/recufiscal" 13 "github.com/benoitkugler/goACVE/server/shared" 14 15 dm "github.com/benoitkugler/goACVE/server/core/datamodel" 16 rd "github.com/benoitkugler/goACVE/server/core/rawdata" 17 18 "github.com/benoitkugler/goACVE/server/core/apiserver" 19 20 "github.com/labstack/echo" 21 ) 22 23 // GetUsers renvoie la liste des utilisateurs du client 24 func (ct Controller) GetUsers(c echo.Context) error { 25 if err := authentifie(c); err != nil { 26 return err 27 } 28 users, err := rd.SelectAllUsers(ct.DB) 29 if err != nil { 30 return err 31 } 32 var out []rd.ClientUser 33 for _, user := range users { 34 out = append(out, rd.ClientUser{Id: user.Id, Label: user.Label.String(), IsAdmin: bool(user.IsAdmin)}) 35 } 36 return c.JSON(200, out) 37 } 38 39 // CheckPassword vérifie le mot de passe de l'utilisateur donné 40 func (ct Controller) CheckPassword(c echo.Context) error { 41 if err := authentifie(c); err != nil { 42 return err 43 } 44 in := new(apiserver.ParamsLoggin) 45 if err := c.Bind(in); err != nil { 46 return fmt.Errorf("Information de loggin invalides : %s", err) 47 } 48 user, err := rd.SelectUser(ct.DB, in.Id) 49 if err != nil { 50 return err 51 } 52 var out apiserver.OutputLoggin 53 if user.Mdp.String() == in.Password { 54 out.Valid = true 55 out.User = user 56 } 57 return c.JSON(200, out) 58 } 59 60 // SertDB charge toute la base de donnée et la renvoie 61 // sous forme compressée 62 func (ct Controller) SertDB(c echo.Context) error { 63 if err := authentifie(c); err != nil { 64 return err 65 } 66 b, err := dm.LoadRemoteBaseLocale(ct.DB) 67 if err != nil { 68 return err 69 } 70 buf := new(bytes.Buffer) 71 if err = b.MarshalCompress(buf); err != nil { 72 return err 73 } 74 c.Response().Header().Add("Content-Length", strconv.Itoa(len(buf.Bytes()))) 75 return c.Stream(200, mime.TypeByExtension(".gz"), buf) 76 } 77 78 // SertDBHash charge toute la base de donnée et calcule un hash 79 // compact, renvoyée encodée (multipart). 80 // Voir SertDBPartiel pour la seconde partie du procédé. 81 func (ct Controller) SertDBHash(c echo.Context) error { 82 if err := authentifie(c); err != nil { 83 return err 84 } 85 b, err := dm.LoadRemoteBaseLocale(ct.DB) 86 if err != nil { 87 return err 88 } 89 hash, err := b.Hash() 90 if err != nil { 91 return shared.FormatErr("Impossible de calculer le hash.", err) 92 } 93 header, bin, err := hash.Compress() 94 if err != nil { 95 return shared.FormatErr("Impossible de compresser le hash.", err) 96 } 97 w := c.Response() 98 err = shared.WriteMultipart(w.Header(), w, map[string][]byte{ 99 apiserver.DBHashHeaderJSONKey: header, 100 apiserver.DBHashBinaryKey: bin, 101 }) 102 103 return err 104 } 105 106 func (ct Controller) SertDBPartiel(c echo.Context) error { 107 if err := authentifie(c); err != nil { 108 return err 109 } 110 var items map[string][]int64 111 if err := c.Bind(&items); err != nil { 112 return err 113 } 114 b, err := dm.LoadRemoteBaseLocalePartiel(ct.DB, items) 115 if err != nil { 116 return err 117 } 118 buf := new(bytes.Buffer) 119 if err = b.MarshalCompress(buf); err != nil { 120 return err 121 } 122 c.Response().Header().Add("Content-Length", strconv.Itoa(len(buf.Bytes()))) 123 return c.Stream(200, mime.TypeByExtension(".gz"), buf) 124 } 125 126 //-------------------------------------------------------------------- 127 //------------------------ Dons -------------------------------------- 128 //-------------------------------------------------------------------- 129 130 // GenereRecuFiscal génère une archive contenant les reçus fiscaux, 131 // et renvoie aussi les dons mis à jour. 132 func (ct Controller) GenereRecuFiscal(c echo.Context) error { 133 if err := authentifie(c); err != nil { 134 return err 135 } 136 in := new(dm.OptionsRecuFiscal) 137 if err := c.Bind(in); err != nil { 138 return fmt.Errorf("Paramètres de reçus fiscaux invalides : %s", err) 139 } 140 141 dons, archive, err := recufiscal.GenereRecuFiscaux(ct.DB, *in) 142 if err != nil { 143 return err 144 } 145 146 donsJson, err := json.Marshal(dons) 147 if err != nil { 148 return err 149 } 150 151 w := c.Response() 152 err = shared.WriteMultipart(w.Header(), w, map[string][]byte{ 153 apiserver.RecusFiscauxJSONKey: donsJson, 154 apiserver.RecusFiscauxZIPKey: archive.Bytes(), 155 }) 156 return err 157 } 158 159 // ImportDonsHelloasso charge et renvoie les dons HelloAsso qui 160 // n'ont pas encore été importé. 161 func (ct Controller) ImportDonsHelloasso(c echo.Context) error { 162 if err := authentifie(c); err != nil { 163 return err 164 } 165 out, err := ct.importDonsHelloasso() 166 if err != nil { 167 return shared.FormatErr("Impossible de charger les dons HelloAsso", err) 168 } 169 return c.JSON(200, out) 170 } 171 172 // IdentifieDonHelloasso crée un nouveau don à partir 173 // des infos HelloAsso et d'un donateur identifié. 174 func (ct Controller) IdentifieDonHelloasso(c echo.Context) error { 175 if err := authentifie(c); err != nil { 176 return err 177 } 178 var params apiserver.IdentifieDonIn 179 if err := c.Bind(¶ms); err != nil { 180 return shared.FormatErr("Paramètres invalides", err) 181 } 182 out, err := ct.identifieDon(params) 183 if err != nil { 184 return shared.FormatErr("Impossible d'identifier le don", err) 185 } 186 return c.JSON(200, out) 187 } 188 189 //-------------------------------------------------------------------- 190 //------------------------ Inscriptions ------------------------------ 191 //-------------------------------------------------------------------- 192 193 // Marque l'inscription comme validée, après s'être assuré 194 // qu'aucune personne impliquée n'est temporaire. 195 // De plus, un mail de dé-verrouillage de la fiche sanitaire 196 // est envoyé si nécessaire. 197 // Renvoie la facture mise à jour. 198 func (ct Controller) ValideInscription(c echo.Context) error { 199 if err := authentifie(c); err != nil { 200 return err 201 } 202 203 id, err := shared.ParseId(c, "id") 204 if err != nil { 205 return err 206 } 207 rows, err := ct.DB.Query(`SELECT personnes.* FROM personnes 208 JOIN factures ON factures.id_personne = personnes.id 209 WHERE factures.id = $1 210 UNION 211 SELECT personnes.* FROM personnes 212 JOIN participants ON participants.id_personne = personnes.id 213 WHERE participants.id_facture = $1`, id) 214 if err != nil { 215 return err 216 } 217 personnes, err := rd.ScanPersonnes(rows) 218 if err != nil { 219 return err 220 } 221 222 // on s'assure qu'aucune personne n'est temporaire 223 for _, personne := range personnes { 224 if personne.IsTemporaire { 225 return fmt.Errorf("%s n'a pas encore été identifié(e) !", personne.NomPrenom()) 226 } 227 } 228 229 // on propose le partage des fiches sanitaires 230 err = ct.checkNotifiePartageFicheSanitaire(c.Request().Host, id) 231 if err != nil { 232 return err 233 } 234 235 row := ct.DB.QueryRow("UPDATE factures SET is_validated = true WHERE id = $1 RETURNING *", id) 236 out, err := rd.ScanFacture(row) 237 if err != nil { 238 return err 239 } 240 return c.JSON(200, out) 241 } 242 243 // DeleteInscription supprime 244 func (ct Controller) DeleteInscription(c echo.Context) error { 245 if err := authentifie(c); err != nil { 246 return err 247 } 248 id, err := shared.ParseId(c, "id") 249 if err != nil { 250 return fmt.Errorf("Id (Inscription) invalide : %s", err) 251 } 252 out, err := ct.deleteInscription(id) 253 if err != nil { 254 return err 255 } 256 return c.JSON(200, out) 257 } 258 259 //----------------------------------------------------------------------- 260 //------------------------ Rapprochements ------------------------------- 261 //----------------------------------------------------------------------- 262 263 // IdentifieEquipier identifie un équipier temporaire 264 func (ct Controller) IdentifieEquipier(c echo.Context) error { 265 if err := authentifie(c); err != nil { 266 return err 267 } 268 in := new(apiserver.IdentifieEquipierIn) 269 if err := c.Bind(in); err != nil { 270 return fmt.Errorf("Paramètres d'identification invalides : %s", err) 271 } 272 out, err := ct.identifieEquipier(*in) 273 if err != nil { 274 return err 275 } 276 return c.JSON(200, out) 277 } 278 279 // IdentifieParticipant identifie un participant temporaire 280 func (ct Controller) IdentifieParticipant(c echo.Context) error { 281 if err := authentifie(c); err != nil { 282 return err 283 } 284 in := new(apiserver.IdentifieParticipantIn) 285 if err := c.Bind(in); err != nil { 286 return fmt.Errorf("Paramètres d'identification invalides : %s", err) 287 } 288 out, err := ct.identifieParticipant(*in) 289 if err != nil { 290 return err 291 } 292 return c.JSON(200, out) 293 } 294 295 // IdentifieResponsable identifie un responsable temporaire 296 func (ct Controller) IdentifieResponsable(c echo.Context) error { 297 if err := authentifie(c); err != nil { 298 return err 299 } 300 in := new(apiserver.IdentifieResponsableIn) 301 if err := c.Bind(in); err != nil { 302 return fmt.Errorf("Paramètres d'identification invalides : %s", err) 303 } 304 out, err := ct.identifieResponsable(*in) 305 if err != nil { 306 return err 307 } 308 return c.JSON(200, out) 309 } 310 311 // IdentifieParticipantsimple identifie un participant simple temporaire 312 // et envoie un message de confirmation. 313 func (ct Controller) IdentifieParticipantsimple(c echo.Context) error { 314 if err := authentifie(c); err != nil { 315 return err 316 } 317 in := new(apiserver.IdentifieParticipantsimpleIn) 318 if err := c.Bind(in); err != nil { 319 return fmt.Errorf("Paramètres d'identification invalides : %s", err) 320 } 321 out, err := ct.identifieParticipantsimple(*in) 322 if err != nil { 323 return err 324 } 325 err = ct.notifieInscriptionSimpleValide(out.Participantsimple) 326 if err != nil { 327 return fmt.Errorf("Le participant a bien été identifié, mais l'envoi d'un mail de confirmation a échoué : %s", 328 err) 329 } 330 return c.JSON(200, out) 331 } 332 333 //-------------------------------------------------------------------- 334 //------------------------ Paiements --------------------------------- 335 //-------------------------------------------------------------------- 336 337 // MarquePaiementsBordereau 338 func (ct Controller) MarquePaiementsBordereau(c echo.Context) error { 339 if err := authentifie(c); err != nil { 340 return err 341 } 342 var in rd.Ids 343 if err := c.Bind(&in); err != nil { 344 return fmt.Errorf("Paramètres d'identification invalides : %s", err) 345 } 346 rows, err := ct.DB.Query("UPDATE paiements SET in_bordereau = $1 WHERE id = ANY($2) RETURNING *", time.Now(), in.AsSQL()) 347 if err != nil { 348 return err 349 } 350 out, err := rd.ScanPaiements(rows) 351 if err != nil { 352 return err 353 } 354 return c.JSON(200, out) 355 } 356 357 //-------------------------------------------------------------------- 358 //------------------------ Documents --------------------------------- 359 //-------------------------------------------------------------------- 360 361 // GetDocumentsMiniatures renvoies les miniatures des documents demandés 362 func (ct Controller) GetDocumentsMiniatures(c echo.Context) error { 363 if err := authentifie(c); err != nil { 364 return err 365 } 366 var in rd.Ids 367 if err := c.Bind(&in); err != nil { 368 return fmt.Errorf("Ids (documents) invalides : %s", err) 369 } 370 rows, err := ct.DB.Query("SELECT id_document, null, miniature FROM contenu_documents WHERE id_document = ANY ($1)", in.AsSQL()) 371 if err != nil { 372 return err 373 } 374 out, err := rd.ScanContenuDocuments(rows) 375 if err != nil { 376 return err 377 } 378 return c.JSON(200, out) 379 } 380 381 // DownloadDocument renvoie le document décompressé demandé 382 func (ct Controller) DownloadDocument(c echo.Context) error { 383 if err := authentifie(c); err != nil { 384 return err 385 } 386 id, err := shared.ParseId(c, "id") 387 if err != nil { 388 return err 389 } 390 contenu, found, err := rd.SelectContenuDocumentByIdDocument(ct.DB, id) 391 if err != nil { 392 return err 393 } 394 if !found { 395 return fmt.Errorf("Le document (id %d) n'a pas de contenu. Veuillez le supprimer.", id) 396 } 397 b := contenu.Contenu 398 c.Response().Header().Add("Content-length", strconv.Itoa(len(b))) 399 return c.Stream(200, "", bytes.NewReader(b)) 400 } 401 402 // CreateDocument créé les meta-données et associe le document à 403 // une cible (personne ou aide) 404 func (ct Controller) CreateDocument(c echo.Context) error { 405 if err := authentifie(c); err != nil { 406 return err 407 } 408 var in apiserver.CreateDocumentIn 409 fileName, fileContent, err := documents.ReceiveUploadWithMeta(c, apiserver.DOCUMENT_MAX_SIZE, &in) 410 if err != nil { 411 return fmt.Errorf("Paramètres invalides : %s", err) 412 } 413 var out apiserver.CreateDocumentIn 414 tx, err := ct.DB.Begin() 415 if err != nil { 416 return err 417 } 418 out.Document, err = in.Document.Insert(tx) 419 if err != nil { 420 return shared.Rollback(tx, err) 421 } 422 switch target := in.Target.(type) { 423 case rd.DocumentPersonne: 424 target.IdDocument = out.Document.Id 425 out.Target = target 426 err = rd.InsertManyDocumentPersonnes(tx, target) 427 case rd.DocumentAide: 428 target.IdDocument = out.Document.Id 429 out.Target = target 430 err = rd.InsertManyDocumentAides(tx, target) 431 } 432 if err != nil { 433 return shared.Rollback(tx, err) 434 } 435 436 out.Document, err = documents.SaveDocument(tx, out.Document.Id, fileContent, fileName, true) 437 if err != nil { 438 return shared.Rollback(tx, err) 439 } 440 441 err = tx.Commit() 442 if err != nil { 443 return err 444 } 445 return c.JSON(200, out) 446 } 447 448 // UploadDocument met à jour le contenu du document 449 func (ct Controller) UploadDocument(c echo.Context) error { 450 if err := authentifie(c); err != nil { 451 return err 452 } 453 id, err := shared.ParseId(c, "id") 454 if err != nil { 455 return fmt.Errorf("Paramètres d'upload invalides : %s", err) 456 } 457 fileHeader, err := c.FormFile("file") 458 if err != nil { 459 return fmt.Errorf("Fichier manquant : %s", err) 460 } 461 filename, content, err := documents.ReceiveUpload(fileHeader, apiserver.DOCUMENT_MAX_SIZE) 462 if err != nil { 463 return err 464 } 465 466 tx, err := ct.DB.Begin() 467 if err != nil { 468 return err 469 } 470 doc, err := documents.SaveDocument(tx, id, content, filename, true) 471 if err != nil { 472 return shared.Rollback(tx, err) 473 } 474 475 if err = tx.Commit(); err != nil { 476 return err 477 } 478 return c.JSON(200, doc) 479 } 480 481 //-------------------------------------------------------------------- 482 //------------------------- Messages --------------------------------- 483 //-------------------------------------------------------------------- 484 485 // NotifieMessage ajoute le message donné et envoie un mail de notification 486 func (ct Controller) NotifieMessage(c echo.Context) error { 487 if err := authentifie(c); err != nil { 488 return err 489 } 490 var in apiserver.NotifieMessageIn 491 if err := c.Bind(&in); err != nil { 492 return err 493 } 494 out, err := ct.creeMessageCentre(c.Request().Host, in.IdFacture, in.Contenu) 495 if err != nil { 496 return err 497 } 498 return c.JSON(200, out) 499 } 500 501 // EditMessage modifie le contenu, sans envoi de mail 502 func (ct Controller) EditMessage(c echo.Context) error { 503 if err := authentifie(c); err != nil { 504 return err 505 } 506 var in apiserver.EditMessageIn 507 if err := c.Bind(&in); err != nil { 508 return err 509 } 510 out, err := ct.editMessageCentre(in) 511 if err != nil { 512 return err 513 } 514 return c.JSON(200, out) 515 } 516 517 // CreateMessageMessage ajoute un message personnalisé, sans 518 // notification. 519 func (ct Controller) CreateMessageMessage(c echo.Context) error { 520 if err := authentifie(c); err != nil { 521 return err 522 } 523 var in apiserver.CreateMessageMessage 524 if err := c.Bind(&in); err != nil { 525 return err 526 } 527 out, err := ct.createMessageMessage(in) 528 if err != nil { 529 return err 530 } 531 return c.JSON(200, out) 532 } 533 534 // NotifieSimple envoie un message sans contenu additionnel 535 func (ct Controller) NotifieSimple(c echo.Context) error { 536 if err := authentifie(c); err != nil { 537 return err 538 } 539 var in apiserver.NotifieSimple 540 if err := c.Bind(&in); err != nil { 541 return err 542 } 543 out, err := ct.notifieSimple(c.Request().Host, in) 544 if err != nil { 545 return err 546 } 547 return c.JSON(200, out) 548 } 549 550 // NotifiePlaceLiberee modifie le participant et 551 // envoie un message 552 func (ct Controller) NotifiePlaceLiberee(c echo.Context) error { 553 if err := authentifie(c); err != nil { 554 return err 555 } 556 var in apiserver.NotifiePlaceLibereeIn 557 if err := c.Bind(&in); err != nil { 558 return err 559 } 560 out, err := ct.notifiePlaceLiberee(c.Request().Host, in) 561 if err != nil { 562 return err 563 } 564 return c.JSON(200, out) 565 } 566 567 // NotifieAttestation envoie un message contenant une attestation 568 func (ct Controller) NotifieAttestation(c echo.Context) error { 569 if err := authentifie(c); err != nil { 570 return err 571 } 572 var in apiserver.NotifieAttestationIn 573 if err := c.Bind(&in); err != nil { 574 return err 575 } 576 out, err := ct.notifieAttestation(c.Request().Host, in) 577 if err != nil { 578 return err 579 } 580 return c.JSON(200, out) 581 } 582 583 // NotifieDocuments stream l'envoi des documents 584 func (ct Controller) NotifieDocuments(c echo.Context) error { 585 if err := authentifie(c); err != nil { 586 return err 587 } 588 var in apiserver.NotifieDocumentsIn 589 if err := c.Bind(&in); err != nil { 590 return err 591 } 592 if err := ct.checkVerrouDocuments(in.IdCamp); err != nil { 593 return err 594 } 595 s := streamDocument{idCamp: in.IdCamp} 596 if err := s.checkListeAttente(in.IdsFactures, ct.DB); err != nil { 597 return err 598 } 599 message := rd.Message{Kind: rd.MDocuments} 600 err := ct.notifieManyMessages(c.Request().Host, s, message, in.IdsFactures, c.Response()) 601 return err 602 } 603 604 // NotifieSondages stream l'envoi des sondages 605 func (ct Controller) NotifieSondages(c echo.Context) error { 606 if err := authentifie(c); err != nil { 607 return err 608 } 609 var in apiserver.NotifieDocumentsIn 610 if err := c.Bind(&in); err != nil { 611 return err 612 } 613 614 message := rd.Message{Kind: rd.MSondage} 615 err := ct.notifieManyMessages(c.Request().Host, streamSondage{idCamp: in.IdCamp}, message, in.IdsFactures, c.Response()) 616 return err 617 } 618 619 // NotifieMany stream l'envoi d'un message à plusieurs dossiers 620 func (ct Controller) NotifieMany(c echo.Context) error { 621 if err := authentifie(c); err != nil { 622 return err 623 } 624 var in apiserver.NotifieManyIn 625 if err := c.Bind(&in); err != nil { 626 return err 627 } 628 629 if in.Contenu.TrimSpace() == "" { 630 return fmt.Errorf("Message vide !") 631 } 632 633 message := rd.Message{Kind: rd.MCentre} 634 err := ct.notifieManyMessages(c.Request().Host, streamMessage{contenu: in.Contenu}, message, in.IdsFactures, c.Response()) 635 return err 636 } 637 638 // LoadInscriptions renvoie les inscriptions brutes, telles 639 // qu'effectuées sur le formulaire publique, sous forme d'un dictionnaire 640 func (ct Controller) LoadInscriptions(c echo.Context) error { 641 if err := authentifie(c); err != nil { 642 return err 643 } 644 out, err := rd.SelectAllInscriptions(ct.DB) 645 if err != nil { 646 return err 647 } 648 return c.JSON(200, out) 649 } 650 651 // FusionneFactures redirige les participants, paiements, messages et 652 // sondages d'un dossier vers un autre, avant de supprimer le dossier 653 // maintenant vide. Un mail de notification peut être envoyé. 654 func (ct Controller) FusionneFactures(c echo.Context) error { 655 if err := authentifie(c); err != nil { 656 return err 657 } 658 var params apiserver.FusionneFacturesIn 659 if err := c.Bind(¶ms); err != nil { 660 return shared.FormatErr("Paramètres invalides", err) 661 } 662 out, err := ct.fusionneFactures(c.Request().Host, params) 663 if err != nil { 664 return err 665 } 666 return c.JSON(200, out) 667 }