github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/server/directeurs/views.go (about)

     1  package directeurs
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"github.com/benoitkugler/goACVE/server/shared"
     9  
    10  	"github.com/avct/uasurfer"
    11  	"github.com/benoitkugler/goACVE/server/documents"
    12  
    13  	"github.com/benoitkugler/goACVE/server/core/apiserver"
    14  	cd "github.com/benoitkugler/goACVE/server/core/documents"
    15  	rd "github.com/benoitkugler/goACVE/server/core/rawdata"
    16  	"github.com/benoitkugler/goACVE/server/core/rawdata/matching"
    17  
    18  	"github.com/labstack/echo"
    19  )
    20  
    21  const (
    22  	UrlApiDirecteurs = "/directeurs/api/"
    23  
    24  	ExportInscrits export = "inscrits"
    25  	ExportEquipe   export = "equipe"
    26  	ExportFinances export = "finances"
    27  
    28  	DetailsDetails details = "details"
    29  	DetailsEnvois  details = "envois"
    30  
    31  	LVCurrent listeVetements = "current"
    32  	LVEte     listeVetements = "ete"
    33  	LVHiver   listeVetements = "hiver"
    34  
    35  	InviteTous formulaireEquipier = "all"
    36  	InviteNew  formulaireEquipier = "new"
    37  	InviteOne  formulaireEquipier = "one"
    38  )
    39  
    40  // Accueil renvoie l'application statique du portail des directeurs
    41  func Accueil(c echo.Context) error {
    42  	ua := uasurfer.Parse(c.Request().UserAgent())
    43  	if ua.Browser.Name == uasurfer.BrowserIE && ua.Browser.Version.Major < 12 {
    44  		return shared.RedirectError(c, errors.New(`Ce portail ne supporte pas Internet Explorer. 
    45  			<br/> Veuillez nous excuser pour le désagrement occasioné. <br/>
    46  			Plusieurs très bons navigateurs libres et gratuits sont disponibles (Mozilla Firefox, Google Chrome, ...).
    47  			`))
    48  	}
    49  	return c.File("server/static/directeurs/index.html")
    50  }
    51  
    52  // DataLoggin renvoie la liste des camps disponibles
    53  func (ct Controller) DataLoggin(c echo.Context) error {
    54  	camps, err := ct.getCamps()
    55  	if err != nil {
    56  		return err
    57  	}
    58  	return c.JSON(200, camps)
    59  }
    60  
    61  // Loggin vérifie le password
    62  func (ct Controller) Loggin(c echo.Context) error {
    63  	var params LogginIn
    64  	if err := c.Bind(&params); err != nil {
    65  		return shared.FormatErr("Champs manquants !", err)
    66  	}
    67  	camp, token, err := ct.checkPassword(params.IdCamp, params.Password)
    68  	if err != nil {
    69  		return err
    70  	}
    71  	var out LogginOut
    72  	if token != "" { // sinon, mauvais mot de passe
    73  		out.Valide = true
    74  		out.Token = token
    75  		out.Camp.From(camp)
    76  		out.LienCompta = string(camp.LienCompta)
    77  	}
    78  	return c.JSON(200, out)
    79  }
    80  
    81  // GetDocumentsEquipe renvoie les exigences de documents des équipiers
    82  func (ct Controller) GetDocumentsEquipe(c echo.Context) error {
    83  	rc, err := ct.setupRequestComplet(c.Request(), loadEquipiers)
    84  	if err != nil {
    85  		return err
    86  	}
    87  	l, err := rc.getPiecesJustificatives(c.Request().Host)
    88  	if err != nil {
    89  		return err
    90  	}
    91  	out := DocumentsEquipeOut{
    92  		Token:  rc.Token(),
    93  		Pieces: l,
    94  	}
    95  	return c.JSON(200, out)
    96  }
    97  
    98  // DownloadDocumentsEquipe renvoie une archive avec plusieurs documents
    99  func (ct Controller) DownloadDocumentsEquipe(c echo.Context) error {
   100  	rc, err := ct.setupRequestComplet(c.Request(), loadEquipiers)
   101  	if err != nil {
   102  		return err
   103  	}
   104  
   105  	onlyRequis := c.QueryParam("only-requis") != ""
   106  	buf, err := rc.downloadDocumentsEquipiers(onlyRequis)
   107  	if err != nil {
   108  		return shared.FormatErr("La compilation des documents a échoué.", err)
   109  	}
   110  	filename := reduitNom(fmt.Sprintf("Documents Equipe %s.zip", rc.Camp().RawData().Label().String()))
   111  	return documents.Attachment(c, filename, buf.Bytes(), true)
   112  }
   113  
   114  // SetDocumentsEquipe met à jour les exigences de documents
   115  func (ct Controller) SetDocumentsEquipe(c echo.Context) error {
   116  	rc, err := ct.setupRequestComplet(c.Request(), loadEquipiers)
   117  	if err != nil {
   118  		return err
   119  	}
   120  
   121  	var args UpdateContrainteEquipierIn
   122  	if err = c.Bind(&args); err != nil {
   123  		return err
   124  	}
   125  	if err := rc.setExigenceDocument(args); err != nil {
   126  		return err
   127  	}
   128  	return c.NoContent(200)
   129  }
   130  
   131  // AddDocumentEquipe upload un document d'un équipier
   132  func (ct Controller) AddDocumentEquipe(c echo.Context) error {
   133  	rc, err := ct.setupRequestComplet(c.Request(), loadEquipiers)
   134  	if err != nil {
   135  		return err
   136  	}
   137  
   138  	var args AddDocumentIn
   139  	fileName, fileContent, err := documents.ReceiveUploadWithMeta(c, apiserver.DOCUMENT_MAX_SIZE, &args)
   140  	if err != nil {
   141  		return shared.FormatErr("Téléversement impossible.", err)
   142  	}
   143  
   144  	newDoc, err := rc.creeDocumentEquipier(c.Request().Host, args.IdEquipier, documents.ParamsNewDocument{
   145  		IdContrainte: args.IdContrainte,
   146  		Description:  args.Description,
   147  		FileContent:  fileContent,
   148  		FileName:     fileName,
   149  	})
   150  	if err != nil {
   151  		return err
   152  	}
   153  	out := AddDocumentOut{
   154  		Token:    rc.Token(),
   155  		Document: newDoc,
   156  	}
   157  	return c.JSON(200, out)
   158  }
   159  
   160  // RechercheProfil renvoie les personnes proches de la recherche
   161  func (ct Controller) RechercheProfil(c echo.Context) error {
   162  	_, token, err := ct.authentifie(c.Request())
   163  	if err != nil {
   164  		return err
   165  	}
   166  
   167  	var args matching.PatternsSimilarite
   168  	if err = c.Bind(&args); err != nil {
   169  		return shared.FormatErr("Le format des critères de recherche est invalide.", err)
   170  	}
   171  	out, err := ct.chercheSimilaires(args)
   172  	if err != nil {
   173  		return shared.FormatErr("La recherche a échoué.", err)
   174  	}
   175  	return c.JSON(200, ChercheSimilaireOut{
   176  		Token:        token,
   177  		Propositions: out,
   178  	})
   179  }
   180  
   181  // GetEquipier renvoie la liste des équipiers
   182  func (ct Controller) GetEquipe(c echo.Context) error {
   183  	rc, err := ct.setupRequestComplet(c.Request(), loadEquipiers)
   184  	if err != nil {
   185  		return err
   186  	}
   187  
   188  	equipe, err := rc.getEquipe(c.Request().Host)
   189  	if err != nil {
   190  		return err
   191  	}
   192  	out := LoadEquipiersOut{
   193  		Token:  rc.Token(),
   194  		Equipe: equipe,
   195  	}
   196  	return c.JSON(200, out)
   197  }
   198  
   199  // AddEquipier ajoute un équipier, temporaire ou non
   200  func (ct Controller) AddEquipier(c echo.Context) error {
   201  	rc, err := ct.setupRequestComplet(c.Request(), loadEquipiers)
   202  	if err != nil {
   203  		return err
   204  	}
   205  
   206  	var args CreateEquipierIn
   207  	if err = c.Bind(&args); err != nil {
   208  		return shared.FormatErr("Nouvel équipier invalide.", err)
   209  	}
   210  	if err := args.Roles.Check(); err != nil {
   211  		return err
   212  	}
   213  	if args.Rattache {
   214  		_, err = rc.rattacheEquipier(args.IdPersonne, args.Roles)
   215  	} else {
   216  		_, err = rc.ajouteEquipierTmp(args.Personne, args.Roles)
   217  	}
   218  	if err != nil {
   219  		return shared.FormatErr("La création de l'équipier a échoué.", err)
   220  	}
   221  	equipe, err := rc.getEquipe(c.Request().Host)
   222  	if err != nil {
   223  		return err
   224  	}
   225  	out := LoadEquipiersOut{
   226  		Token:  rc.Token(),
   227  		Equipe: equipe,
   228  	}
   229  	return c.JSON(200, out)
   230  }
   231  
   232  // ModifieEquipier met à jour un équipier et la personne sous-jacente
   233  func (ct Controller) ModifieEquipier(c echo.Context) error {
   234  	rc, err := ct.setupRequestComplet(c.Request(), loadEquipiers)
   235  	if err != nil {
   236  		return err
   237  	}
   238  
   239  	var args EquipierDirecteur
   240  	if err = c.Bind(&args); err != nil {
   241  		return shared.FormatErr("Equipier invalide.", err)
   242  	}
   243  	if err = rc.modifieEquipier(args); err != nil {
   244  		return shared.FormatErr("Impossible de modifier l'équipier", err)
   245  	}
   246  	equipe, err := rc.getEquipe(c.Request().Host)
   247  	if err != nil {
   248  		return err
   249  	}
   250  	out := LoadEquipiersOut{
   251  		Token:  rc.Token(),
   252  		Equipe: equipe,
   253  	}
   254  	return c.JSON(200, out)
   255  }
   256  
   257  // DeleteEquipier supprime l'équipier (et la personne temporaire
   258  // le cas échéant)
   259  func (ct Controller) DeleteEquipier(c echo.Context) error {
   260  	rc, err := ct.setupRequestComplet(c.Request(), loadEquipiers)
   261  	if err != nil {
   262  		return err
   263  	}
   264  
   265  	id, err := shared.ParseId(c, "id")
   266  	if err != nil {
   267  		return err
   268  	}
   269  	if err = rc.deleteEquipier(id); err != nil {
   270  		return shared.FormatErr("Impossible de supprimer l'équipier", err)
   271  	}
   272  	equipe, err := rc.getEquipe(c.Request().Host)
   273  	if err != nil {
   274  		return err
   275  	}
   276  	out := LoadEquipiersOut{
   277  		Token:  rc.Token(),
   278  		Equipe: equipe,
   279  	}
   280  	return c.JSON(200, out)
   281  }
   282  
   283  // InviteFormulaireEquipier envoie un mail d'invitation
   284  // à remplir le formulaire équipier
   285  func (ct Controller) InviteFormulaireEquipier(c echo.Context) error {
   286  	rc, err := ct.setupRequestComplet(c.Request(), loadEquipiers)
   287  	if err != nil {
   288  		return err
   289  	}
   290  
   291  	var args InviteFormulaireIn
   292  	if err = c.Bind(&args); err != nil {
   293  		return shared.FormatErr("Paramètres invalides.", err)
   294  	}
   295  	switch args.Mode {
   296  	case InviteOne:
   297  		err = rc.inviteFormulaireEquipier(c.Request().Host, args.IdParticipant)
   298  	case InviteNew, InviteTous:
   299  		err = rc.inviteFormulairesEquipiers(c.Request().Host, args.Mode == InviteNew)
   300  	default:
   301  		return fmt.Errorf("Mode non supporté : %s", args.Mode)
   302  	}
   303  	if err != nil {
   304  		return err
   305  	}
   306  	equipe, err := rc.getEquipe(c.Request().Host)
   307  	if err != nil {
   308  		return err
   309  	}
   310  	out := LoadEquipiersOut{
   311  		Token:  rc.Token(),
   312  		Equipe: equipe,
   313  	}
   314  	return c.JSON(200, out)
   315  }
   316  
   317  // GetInscrits renvoie la liste des participants
   318  func (ct Controller) GetInscrits(c echo.Context) error {
   319  	rc, err := ct.setupRequest(c.Request(), loadInscrits)
   320  	if err != nil {
   321  		return err
   322  	}
   323  
   324  	insc, err := rc.getInscrits(c.Request().Host)
   325  	if err != nil {
   326  		return shared.FormatErr("Renvoi des inscrits impossible.", err)
   327  	}
   328  	out := LoadInscritsOut{
   329  		Token:    rc.Token(),
   330  		Inscrits: insc,
   331  	}
   332  	return c.JSON(200, out)
   333  }
   334  
   335  // UpdateInscrit met à jour le profil d'un inscrit et renvoie la liste
   336  // mise à jour
   337  func (ct Controller) UpdateInscrit(c echo.Context) error {
   338  	rc, err := ct.setupRequest(c.Request(), loadInscrits)
   339  	if err != nil {
   340  		return err
   341  	}
   342  
   343  	var args UpdateInscritIn
   344  	if err = c.Bind(&args); err != nil {
   345  		return shared.FormatErr("Champs invalides.", err)
   346  	}
   347  	if err = rc.modifieInscrit(args.Modifications, args.Id); err != nil {
   348  		return shared.FormatErr("La modification du participant a échoué.", err)
   349  	}
   350  	insc, err := rc.getInscrits(c.Request().Host)
   351  	if err != nil {
   352  		return shared.FormatErr("Renvoi des inscrits impossible.", err)
   353  	}
   354  	out := LoadInscritsOut{
   355  		Token:    rc.Token(),
   356  		Inscrits: insc,
   357  	}
   358  	return c.JSON(200, out)
   359  }
   360  
   361  // LoadContraintes renvoie les contraintes accessibles par le séjour
   362  func (ct Controller) LoadContraintes(c echo.Context) error {
   363  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   364  	if err != nil {
   365  		return err
   366  	}
   367  	contraintes, err := rc.loadContraintes(c.Request().Host)
   368  	if err != nil {
   369  		return err
   370  	}
   371  	out := LoadContraintesOut{
   372  		Token:       rc.Token(),
   373  		Contraintes: contraintes,
   374  	}
   375  	return c.JSON(200, out)
   376  }
   377  
   378  // CreateContrainte ajoute la contrainte et renvoie les contraintes mise à jour
   379  func (ct Controller) CreateContrainte(c echo.Context) error {
   380  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   381  	if err != nil {
   382  		return err
   383  	}
   384  	var args rd.Contrainte
   385  	if err := c.Bind(&args); err != nil {
   386  		return err
   387  	}
   388  	if err := rc.createContrainte(args); err != nil {
   389  		return err
   390  	}
   391  	contraintes, err := rc.loadContraintes(c.Request().Host)
   392  	if err != nil {
   393  		return err
   394  	}
   395  	out := LoadContraintesOut{
   396  		Token:       rc.Token(),
   397  		Contraintes: contraintes,
   398  	}
   399  	return c.JSON(200, out)
   400  }
   401  
   402  // UpdateContrainte met à jour la contrainte
   403  func (ct Controller) UpdateContrainte(c echo.Context) error {
   404  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   405  	if err != nil {
   406  		return err
   407  	}
   408  	var args rd.Contrainte
   409  	if err := c.Bind(&args); err != nil {
   410  		return err
   411  	}
   412  	contrainte, err := rc.updateContrainte(args)
   413  	if err != nil {
   414  		return err
   415  	}
   416  	out := UpdateContrainteOut{
   417  		Token:      rc.Token(),
   418  		Contrainte: contrainte,
   419  	}
   420  	return c.JSON(200, out)
   421  }
   422  
   423  // LieDocument prépare l'ajout d'un document à la contrainte donnée
   424  func (ct Controller) LieDocument(c echo.Context) error {
   425  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   426  	if err != nil {
   427  		return err
   428  	}
   429  	idContrainte, err := shared.ParseId(c, "id")
   430  	if err != nil {
   431  		return err
   432  	}
   433  	doc, err := rc.lieDocument(c.Request().Host, idContrainte)
   434  	if err != nil {
   435  		return err
   436  	}
   437  	out := LieDocumentOut{
   438  		Token:    rc.Token(),
   439  		Document: doc,
   440  	}
   441  	return c.JSON(200, out)
   442  }
   443  
   444  // DeleteContrainte supprime la contrainte personnalisée et tous les documents associés
   445  // Les contraintes doivent être chargées à nouveau
   446  func (ct Controller) DeleteContrainte(c echo.Context) error {
   447  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   448  	if err != nil {
   449  		return err
   450  	}
   451  	idContrainte, err := shared.ParseId(c, "id")
   452  	if err != nil {
   453  		return err
   454  	}
   455  	nbDocs, err := rc.deleteContrainte(idContrainte)
   456  	if err != nil {
   457  		return err
   458  	}
   459  	out := DeleteContrainteOut{
   460  		Token:       rc.Token(),
   461  		NbDocuments: nbDocs,
   462  	}
   463  	return c.JSON(200, out)
   464  }
   465  
   466  // LoadGroupes renvois les groupes du séjour
   467  func (ct Controller) LoadGroupes(c echo.Context) error {
   468  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   469  	if err != nil {
   470  		return err
   471  	}
   472  	groupes, campContraintes, groupeContraintes, err := loadGroupes(rc.DB, rc.camp.Id)
   473  	if err != nil {
   474  		return err
   475  	}
   476  	out := LoadGroupesOut{
   477  		Token:             rc.Token(),
   478  		Groupes:           groupes,
   479  		CampContraintes:   campContraintes,
   480  		GroupeContraintes: groupeContraintes,
   481  	}
   482  	return c.JSON(200, out)
   483  }
   484  
   485  // CreateGroupe ajoute un groupe au séjour et renvois les groupe mis à jour
   486  // seul le champ 'nom' est utilisé
   487  func (ct Controller) CreateGroupe(c echo.Context) error {
   488  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   489  	if err != nil {
   490  		return err
   491  	}
   492  	var args rd.Groupe
   493  	if err := c.Bind(&args); err != nil {
   494  		return err
   495  	}
   496  	args, err = rc.createGroupe(args)
   497  	if err != nil {
   498  		return err
   499  	}
   500  
   501  	out := UpdateGroupeOut{
   502  		Token:  rc.Token(),
   503  		Groupe: args,
   504  	}
   505  	return c.JSON(200, out)
   506  }
   507  
   508  func (ct Controller) UpdateGroupe(c echo.Context) error {
   509  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   510  	if err != nil {
   511  		return err
   512  	}
   513  	var args rd.Groupe
   514  	if err := c.Bind(&args); err != nil {
   515  		return err
   516  	}
   517  	args, err = rc.updateGroupe(args)
   518  	if err != nil {
   519  		return err
   520  	}
   521  	out := UpdateGroupeOut{
   522  		Token:  rc.Token(),
   523  		Groupe: args,
   524  	}
   525  	return c.JSON(200, out)
   526  }
   527  
   528  // DeleteGroupe supprime le groupe donné et renvois les groupes mis à jour
   529  // Les participants doivent être rechargés aussi
   530  func (ct Controller) DeleteGroupe(c echo.Context) error {
   531  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   532  	if err != nil {
   533  		return err
   534  	}
   535  
   536  	idGroupe, err := shared.ParseId(c, "id")
   537  	if err != nil {
   538  		return err
   539  	}
   540  	err = rc.deleteGroupe(idGroupe)
   541  	if err != nil {
   542  		return err
   543  	}
   544  	groupes, campContraintes, groupeContraintes, err := loadGroupes(rc.DB, rc.camp.Id)
   545  	if err != nil {
   546  		return err
   547  	}
   548  	out := LoadGroupesOut{
   549  		Token:             rc.Token(),
   550  		Groupes:           groupes,
   551  		CampContraintes:   campContraintes,
   552  		GroupeContraintes: groupeContraintes,
   553  	}
   554  	return c.JSON(200, out)
   555  }
   556  
   557  // UpdatePlages met à jour les plages des groupes et les participants
   558  // Les inscrits doivent être rechargés
   559  func (ct Controller) UpdatePlages(c echo.Context) error {
   560  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   561  	if err != nil {
   562  		return err
   563  	}
   564  	var args UpdatePlageIn
   565  	if err := c.Bind(&args); err != nil {
   566  		return err
   567  	}
   568  	nbParts, err := rc.updatePlages(args.Groupes, args.Erase)
   569  	if err != nil {
   570  		return err
   571  	}
   572  	out := UpdatePlageOut{Token: rc.Token(), NbParticipants: nbParts}
   573  	return c.JSON(200, out)
   574  }
   575  
   576  // UpdateGroupesContraintes met à jour les documents demandés pour chaque groupe
   577  // et renvoie les groupes mis à jour
   578  func (ct Controller) UpdateGroupesContraintes(c echo.Context) error {
   579  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   580  	if err != nil {
   581  		return err
   582  	}
   583  	var args DemandeContraintesIn
   584  	if err := c.Bind(&args); err != nil {
   585  		return err
   586  	}
   587  	err = rc.updateGroupesContraintes(args)
   588  	if err != nil {
   589  		return err
   590  	}
   591  	groupes, campContraintes, groupeContraintes, err := loadGroupes(rc.DB, rc.camp.Id)
   592  	if err != nil {
   593  		return err
   594  	}
   595  	out := LoadGroupesOut{
   596  		Token:             rc.Token(),
   597  		Groupes:           groupes,
   598  		CampContraintes:   campContraintes,
   599  		GroupeContraintes: groupeContraintes,
   600  	}
   601  	return c.JSON(200, out)
   602  
   603  }
   604  
   605  // LoadGroupeAnimateurs renvoie les animateurs de référence
   606  func (ct Controller) LoadGroupeAnimateurs(c echo.Context) error {
   607  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   608  	if err != nil {
   609  		return err
   610  	}
   611  	idGroupe, err := shared.ParseId(c, "id")
   612  	if err != nil {
   613  		return err
   614  	}
   615  	out, err := rc.loadGroupeAnimateurs(idGroupe)
   616  	if err != nil {
   617  		return err
   618  	}
   619  	out.Token = rc.Token()
   620  	return c.JSON(200, out)
   621  }
   622  
   623  // AddGroupeAnimateurs ajoute des animateurs à un groupe
   624  func (ct Controller) AddGroupeAnimateurs(c echo.Context) error {
   625  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   626  	if err != nil {
   627  		return err
   628  	}
   629  	var params AddGroupeAnimateursIn
   630  	if err := c.Bind(&params); err != nil {
   631  		return err
   632  	}
   633  	err = rc.addGroupeAnimateurs(params)
   634  	if err != nil {
   635  		return err
   636  	}
   637  	out, err := rc.loadGroupeAnimateurs(params.IdGroupe)
   638  	if err != nil {
   639  		return err
   640  	}
   641  	out.Token = rc.Token()
   642  	return c.JSON(200, out)
   643  }
   644  
   645  // DeleteGroupeAnimateur supprime l'animateurs d'un groupe
   646  // ainsi que tous les liens inscrits
   647  func (ct Controller) DeleteGroupeAnimateur(c echo.Context) error {
   648  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   649  	if err != nil {
   650  		return err
   651  	}
   652  	var params DeleteGroupeAnimateurIn
   653  	if err := c.Bind(&params); err != nil {
   654  		return err
   655  	}
   656  	err = rc.deleteGroupeAnimateur(params)
   657  	if err != nil {
   658  		return err
   659  	}
   660  	out, err := rc.loadGroupeAnimateurs(params.IdGroupe)
   661  	if err != nil {
   662  		return err
   663  	}
   664  	out.Token = rc.Token()
   665  	return c.JSON(200, out)
   666  }
   667  
   668  // UpdateInscritsAnimateur associe les inscrits à l'animateur,
   669  // et renvoie les liens (complets) du groupe
   670  func (ct Controller) UpdateInscritsAnimateur(c echo.Context) error {
   671  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   672  	if err != nil {
   673  		return err
   674  	}
   675  	var params UpdateInscritsAnimateurIn
   676  	if err := c.Bind(&params); err != nil {
   677  		return err
   678  	}
   679  	pe, err := rc.updateInscritsAnimateur(params)
   680  	if err != nil {
   681  		return err
   682  	}
   683  	out := UpdateInsritsAnimateurOut{
   684  		Token:                rc.Token(),
   685  		ParticipantEquipiers: pe,
   686  	}
   687  	return c.JSON(200, out)
   688  }
   689  
   690  // AutoRepartitInscritsAnimateur propose et applique une répartition des inscrits du groupe,
   691  // en utilisant les critères de sexe, puis d'âge
   692  // Les affections courantes ne sont pas modifiées, seul les inscrits sans animateur sont affectés
   693  func (ct Controller) AutoRepartitInscritsAnimateur(c echo.Context) error {
   694  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   695  	if err != nil {
   696  		return err
   697  	}
   698  	idGroupe, err := shared.ParseId(c, "id-groupe")
   699  	if err != nil {
   700  		return err
   701  	}
   702  	pe, err := rc.autoRepartitionAnimateurs(idGroupe)
   703  	if err != nil {
   704  		return err
   705  	}
   706  	out := UpdateInsritsAnimateurOut{
   707  		Token:                rc.Token(),
   708  		ParticipantEquipiers: pe,
   709  	}
   710  	return c.JSON(200, out)
   711  }
   712  
   713  // PreviewDocumentInscrits renvoie le nombre de documents demandés
   714  // et mis en ligne (en terme de participants)
   715  func (ct Controller) PreviewDocumentInscrits(c echo.Context) error {
   716  	rc, err := ct.setupRequestComplet(c.Request(), loadInscrits)
   717  	if err != nil {
   718  		return err
   719  	}
   720  
   721  	idContrainte, err := shared.ParseId(c, "id-contrainte")
   722  	if err != nil {
   723  		return err
   724  	}
   725  
   726  	out := rc.previewDocsContrainte(idContrainte)
   727  	return c.JSON(200, out)
   728  }
   729  
   730  // DownloadDocumentInscrits télécharge une archive des documents
   731  // des inscrits correspondant à la contrainte donnée.
   732  func (ct Controller) DownloadDocumentInscrits(c echo.Context) error {
   733  	rc, err := ct.setupRequestComplet(c.Request(), loadInscrits)
   734  	if err != nil {
   735  		return err
   736  	}
   737  
   738  	var args rd.OptionnalId
   739  	if err := c.Bind(&args); err != nil {
   740  		return err
   741  	}
   742  
   743  	buf, err := rc.downloadDocsParticipants(args)
   744  	if err != nil {
   745  		return shared.FormatErr("La compilation des documents a échoué.", err)
   746  	}
   747  	filename := reduitNom(fmt.Sprintf("Documents inscrits %s.zip", rc.Camp().RawData().Label().String()))
   748  	return documents.Attachment(c, filename, buf.Bytes(), true)
   749  }
   750  
   751  // DownloadFicheSanitaire télécharge une ou plusieurs fiches sanitaires
   752  func (ct Controller) DownloadFicheSanitaire(c echo.Context) error {
   753  	rc, err := ct.setupRequestComplet(c.Request(), loadInscrits)
   754  	if err != nil {
   755  		return err
   756  	}
   757  
   758  	var args DownloadFicheSanitaireIn
   759  	if err = c.Bind(&args); err != nil {
   760  		return shared.FormatErr("Paramètres d'export invalides.", err)
   761  	}
   762  	var (
   763  		buf      *bytes.Buffer
   764  		filename string
   765  	)
   766  
   767  	switch args.Mode {
   768  	case DownloadOne:
   769  		buf, filename, err = rc.downloadFicheSanitaire(args.IdParticipant)
   770  	case DownloadAll:
   771  		filename = "fiches_sanitaires_vaccins.zip"
   772  		buf, err = rc.downloadFichesSanitaires(args.OnlyMineurs)
   773  	case DownloadAllInOneDocument:
   774  		filename = "fiches_sanitaires.pdf"
   775  		buf, err = rc.downloadFichesSanitairesOneDocument(args.OnlyMineurs, args.TriGroupe)
   776  	default:
   777  		return fmt.Errorf("Mode de téléchargement inconnu : %s", args.Mode)
   778  	}
   779  	if err != nil {
   780  		return shared.FormatErr("La création des fiches sanitaires a échoué.", err)
   781  	}
   782  	return documents.Attachment(c, filename, buf.Bytes(), true)
   783  }
   784  
   785  // ExportsExcel permet de télécharger un document
   786  func (ct Controller) ExportsExcel(c echo.Context) error {
   787  	ex := export(c.Param("categorie"))
   788  	load := loadInscrits
   789  	if ex == ExportEquipe {
   790  		load = loadEquipiers
   791  	}
   792  
   793  	rc, err := ct.setupRequest(c.Request(), load)
   794  	if err != nil {
   795  		return err
   796  	}
   797  
   798  	var (
   799  		filename string
   800  		buf      *bytes.Buffer
   801  	)
   802  	switch ex {
   803  	case ExportInscrits:
   804  		options := newOptionsExportExcel(c)
   805  		buf, err = rc.exportListeInscrits(options)
   806  		filename = "liste_participants"
   807  	case ExportFinances:
   808  		buf, err = rc.exportListeFinances()
   809  		filename = "liste_finances"
   810  	case ExportEquipe:
   811  		buf, err = rc.exportListeEquipiers()
   812  		filename = "liste_equipiers"
   813  	default:
   814  		return fmt.Errorf("Type d'export inconnu : %s", ex)
   815  	}
   816  	if err != nil {
   817  		return shared.FormatErr("La génération de la liste a échoué.", err)
   818  	}
   819  	filename = reduitNom(fmt.Sprintf("%s %s.xlsx", filename, rc.Camp().RawData().Label().String()))
   820  	return documents.Attachment(c, filename, buf.Bytes(), true)
   821  }
   822  
   823  // GetDetails renvoie les paramètres du camp
   824  func (ct Controller) GetDetails(c echo.Context) error {
   825  	rc, err := ct.setupRequest(c.Request(), noLoad)
   826  	if err != nil {
   827  		return err
   828  	}
   829  
   830  	de := details(c.Param("categorie"))
   831  	var out interface{}
   832  	switch de {
   833  	case DetailsDetails:
   834  		out = DetailsDetailsOutput{
   835  			Token:   rc.Token(),
   836  			Details: rc.getDetails(),
   837  		}
   838  	case DetailsEnvois:
   839  		docs, err := rc.getBonusDocs(c.Request().Host)
   840  		if err != nil {
   841  			return err
   842  		}
   843  		out = DetailsEnvoisOut{
   844  			Token:         rc.Token(),
   845  			Envois:        rc.Camp().RawData().Envois,
   846  			PiecesJointes: docs,
   847  		}
   848  	default:
   849  		return fmt.Errorf("Type de détails inconnu : %s", de)
   850  	}
   851  	return c.JSON(200, out)
   852  
   853  }
   854  
   855  // UpdateDetails met à jour certains paramètres du séjour
   856  func (ct Controller) UpdateDetails(c echo.Context) error {
   857  	rc, err := ct.setupRequest(c.Request(), noLoad)
   858  	if err != nil {
   859  		return err
   860  	}
   861  
   862  	de := details(c.Param("categorie"))
   863  	var out interface{}
   864  	switch de {
   865  	case DetailsDetails:
   866  		var det DetailsWritable
   867  		if err = c.Bind(&det); err != nil {
   868  			return shared.FormatErr("Paramètres invalides", err)
   869  		}
   870  		if err = rc.updateDetails(det); err != nil {
   871  			return shared.FormatErr("La mise à jour des détails a échoué.", err)
   872  		}
   873  		out = DetailsDetailsOutput{
   874  			Token:   rc.Token(),
   875  			Details: rc.getDetails(),
   876  		}
   877  	case DetailsEnvois:
   878  		var env rd.Envois
   879  		if err = c.Bind(&env); err != nil {
   880  			return shared.FormatErr("Paramètres d'envoi invalides", err)
   881  		}
   882  		if err = rc.updateEnvois(env); err != nil {
   883  			return shared.FormatErr("La mise à jour des préférences d'envoi a échoué.", err)
   884  		}
   885  		out = DetailsEnvoisOut{
   886  			Token:  rc.Token(),
   887  			Envois: rc.Camp().RawData().Envois,
   888  		}
   889  	default:
   890  		return fmt.Errorf("Type de détails inconnu : %s", de)
   891  	}
   892  	return c.JSON(200, out)
   893  }
   894  
   895  // AjouteBonusDoc upload une pièce jointe additionelle
   896  func (ct Controller) AjouteBonusDoc(c echo.Context) error {
   897  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   898  	if err != nil {
   899  		return err
   900  	}
   901  	fileHeader, err := c.FormFile("file")
   902  	if err != nil {
   903  		return shared.FormatErr("Fichier manquant.", err)
   904  	}
   905  	fileName, fileContent, err := documents.ReceiveUpload(fileHeader, apiserver.DOCUMENT_MAX_SIZE)
   906  	if err != nil {
   907  		return shared.FormatErr("L'ajout du document a échoué.", err)
   908  	}
   909  	pub, err := rc.addBonusDoc(c.Request().Host, fileName, fileContent)
   910  	if err != nil {
   911  		return shared.FormatErr("La création du document a échoué", err)
   912  	}
   913  	out := AddBonusDocOut{
   914  		Token:    rc.Token(),
   915  		Document: pub,
   916  	}
   917  	return c.JSON(200, out)
   918  }
   919  
   920  // GetListeVetements renvoie la liste de vêtements
   921  // actuelle, ou une par défaut
   922  func (ct Controller) GetListeVetements(c echo.Context) error {
   923  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   924  	if err != nil {
   925  		return err
   926  	}
   927  	var out ListeVetementsOut
   928  	lv := listeVetements(c.Param("default"))
   929  	switch lv {
   930  	case LVCurrent:
   931  		out.Liste = rc.Camp().RawData().ListeVetements
   932  	case LVEte:
   933  		out.Liste.Liste = ct.defaultListe.Ete
   934  	case LVHiver:
   935  		out.Liste.Liste = ct.defaultListe.Hiver
   936  	default:
   937  		return fmt.Errorf("Type de liste inconnu : %s", lv)
   938  	}
   939  	out.Token = rc.Token()
   940  	return c.JSON(200, out)
   941  }
   942  
   943  // UpdateListeVetements met à jour la liste de vêtements
   944  func (ct Controller) UpdateListeVetements(c echo.Context) error {
   945  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   946  	if err != nil {
   947  		return err
   948  	}
   949  	var args rd.ListeVetements
   950  	if err = c.Bind(&args); err != nil {
   951  		return shared.FormatErr("Liste de vêtements invalide !", err)
   952  	}
   953  	if err = rc.updateListeVetements(args); err != nil {
   954  		return shared.FormatErr("La modification de la liste de vêtements a échoué.", err)
   955  	}
   956  	out := ListeVetementsOut{
   957  		Token: rc.Token(),
   958  		Liste: rc.Camp().RawData().ListeVetements,
   959  	}
   960  	return c.JSON(200, out)
   961  }
   962  
   963  // PreviewListeVetements génère le document contenant la liste de vêtements
   964  func (ct Controller) PreviewListeVetements(c echo.Context) error {
   965  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   966  	if err != nil {
   967  		return err
   968  	}
   969  
   970  	docR := cd.NewListeVetements(rc.Camp().RawData())
   971  	byt, err := docR.Generate()
   972  	if err != nil {
   973  		return shared.FormatErr("La création de la liste a échoué.", err)
   974  	}
   975  	return documents.Attachment(c, docR.FileName(), byt, true)
   976  }
   977  
   978  // GetLettreDirecteur renvoie le HTML de la lettre, et un éventuel
   979  // document publique.
   980  func (ct Controller) GetLettreDirecteur(c echo.Context) error {
   981  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   982  	if err != nil {
   983  		return err
   984  	}
   985  	var out LettreDirecteurOut
   986  	out.Document, out.Lettre, err = rc.getLettreDirecteur(c.Request().Host)
   987  	if err != nil {
   988  		return err
   989  	}
   990  	out.Token = rc.Token()
   991  	return c.JSON(200, out)
   992  }
   993  
   994  // UpdateLettreDirecteur met à jour le contenu de la lettre et la publie
   995  func (ct Controller) UpdateLettreDirecteur(c echo.Context) error {
   996  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
   997  	if err != nil {
   998  		return err
   999  	}
  1000  	var args rd.Lettredirecteur
  1001  	if err = c.Bind(&args); err != nil {
  1002  		return shared.FormatErr("Paramètres invalides.", err)
  1003  	}
  1004  	doc, err := rc.updateLettreDirecteur(c.Request().Host, args)
  1005  	if err != nil {
  1006  		return shared.FormatErr("La création de la lettre a échoué.", err)
  1007  	}
  1008  	out := LettreDirecteurOut{
  1009  		Token:    rc.Token(),
  1010  		Lettre:   args,
  1011  		Document: doc,
  1012  	}
  1013  	return c.JSON(200, out)
  1014  }
  1015  
  1016  // GetJoomeo renvoie les informations relatives au compte Joomeo du séjour
  1017  func (ct Controller) GetJoomeo(c echo.Context) error {
  1018  	rc, err := ct.setupRequest(c.Request(), noLoad)
  1019  	if err != nil {
  1020  		return err
  1021  	}
  1022  	data, err := rc.loadJoomeoData()
  1023  	if err != nil {
  1024  		return shared.FormatErr("La lecture des informations JOOMEO a échoué.", err)
  1025  	}
  1026  	out := LoadJoomeoOut{
  1027  		Token:      rc.Token(),
  1028  		JoomeoData: data,
  1029  	}
  1030  	return c.JSON(200, out)
  1031  }
  1032  
  1033  // AddContactsJoomeo ajoute plusieurs contacts au séjour
  1034  func (ct Controller) AddContactsJoomeo(c echo.Context) error {
  1035  	rc, err := ct.setupRequest(c.Request(), noLoad)
  1036  	if err != nil {
  1037  		return err
  1038  	}
  1039  
  1040  	var args AddContactJoomeoIn
  1041  	if err = c.Bind(&args); err != nil {
  1042  		return shared.FormatErr("Arguments invalides.", err)
  1043  	}
  1044  	var out AddContactJoomeoOut
  1045  	out.Contacts, out.Errors, err = rc.addJoomeoContacts(args.Mails, args.SendMail)
  1046  	if err != nil {
  1047  		return shared.FormatErr("L'envoi des invitations a échoué.", err)
  1048  	}
  1049  	out.Token = rc.Token()
  1050  	return c.JSON(200, out)
  1051  }
  1052  
  1053  // SetContactUploader élève les permissions du contact
  1054  func (ct Controller) SetContactUploader(c echo.Context) error {
  1055  	rc, err := ct.setupRequest(c.Request(), noLoad)
  1056  	if err != nil {
  1057  		return err
  1058  	}
  1059  
  1060  	var args SetContactUploaderIn
  1061  	if err = c.Bind(&args); err != nil {
  1062  		return shared.FormatErr("Arguments invalides.", err)
  1063  	}
  1064  	var (
  1065  		out             SetContactUploaderOut
  1066  		errSuperContact error
  1067  	)
  1068  	out.Contacts, errSuperContact, err = rc.setContactUploader(args.Contactid)
  1069  	if errSuperContact != nil {
  1070  		out.ErrSuperContact = errSuperContact.Error()
  1071  	}
  1072  	if err != nil {
  1073  		return shared.FormatErr("La modification du contact a échoué.", err)
  1074  	}
  1075  	out.Token = rc.Token()
  1076  	return c.JSON(200, out)
  1077  }
  1078  
  1079  // DeleteContact enlève le contact des contacts Joomeo
  1080  func (ct Controller) DeleteContact(c echo.Context) error {
  1081  	rc, err := ct.setupRequest(c.Request(), noLoad)
  1082  	if err != nil {
  1083  		return err
  1084  	}
  1085  
  1086  	id := c.QueryParam("contactid")
  1087  	if id == "" {
  1088  		return errors.New("Id non fourni !")
  1089  	}
  1090  	var out DeleteContactOut
  1091  	out.Contacts, err = rc.deleteContact(id)
  1092  	if err != nil {
  1093  		return shared.FormatErr("La suppression du contact a échoué.", err)
  1094  	}
  1095  	out.Token = rc.Token()
  1096  	return c.JSON(200, out)
  1097  }
  1098  
  1099  // LoadSondages renvoie les retours sur le séjour.
  1100  func (ct Controller) LoadSondages(c echo.Context) error {
  1101  	rc, err := ct.setupRequestComplet(c.Request(), noLoad)
  1102  	if err != nil {
  1103  		return err
  1104  	}
  1105  	var out LoadSondagesOut
  1106  	out.Sondages, err = rc.loadSondages()
  1107  	if err != nil {
  1108  		return err
  1109  	}
  1110  	out.Token = rc.Token()
  1111  	return c.JSON(200, out)
  1112  }