Source: personne/serviceGroupe.js


'use strict'

const flow = require('an-flow')
const { getNormalizedName } = require('../lib/normalize')

// nos 3 cas
const suivis = ['groupesSuivis']
const membre = ['groupesMembre']
const both = ['groupesMembre', 'groupesSuivis']

/**
 * Helper des controleurs de groupe (api et html)
 * @private
 */
module.exports = function (component) {
  component.service('$groupe', function ($session, $accessControl, $groupeRepository, $personneRepository) {
    // méthodes privées

    /**
     * Ajoute un groupe à l'utilisateur courant
     * @private
     * @param {Context} context
     * @param {string} nom Nom du groupe
     * @param {string[]} groupTypes tableau dont les éléments ne peuvent être que les strings groupesMembre ou groupesSuivis
     * @param {callbackPersonne} next
     */
    function addGroup (context, nom, groupTypes, next) {
      loadCurrentUser(context, function (error, me) {
        if (error) return next(error)
        let hasChanged = false
        groupTypes.forEach(prop => {
          if (!me[prop]) me[prop] = []
          if (me[prop].includes(nom)) {
            log.debug(`Le groupe ${nom} était déjà dans ${prop} pour le user ${me.oid}`)
          } else {
            log.debug('groupe ' + nom + ' ajouté à ' + prop)
            me[prop].push(nom)
            hasChanged = true
          }
        })
        if (hasChanged) saveCurrentUser(context, me, next)
        else next(null, me)
      })
    }

    /**
     * Retourne le nom du groupe (helper des fcts qui prennent un argument groupe|groupeNom)
     * @private
     * @param {string|Groupe} groupe Le groupe ou son nom
     * @returns {string} undefined si groupe n'est ni une string ni un objet avec une propriété nom
     */
    function getNom (groupe) {
      if (typeof groupe === 'string') return groupe
      if (groupe && groupe.nom) return groupe.nom
      log.error('getNom appelé avec un paramètre incorrect', groupe)
    }

    /**
     * Récupère le user courant en bdd
     * @private
     * @param {Context} context
     * @param {callbackPersonne} next
     */
    function loadCurrentUser (context, next) {
      const myOid = $accessControl.getCurrentUserOid(context)
      if (!myOid) throw Error('Pas d’utilisateur en session')
      $personneRepository.load(myOid, next)
    }

    /**
     * Retire un groupe à l'utilisateur courant
     * @private
     * @param {Context} context
     * @param {string} nom Nom du groupe
     * @param {string[]} groupTypes tableau dont les éléments ne peuvent être que les strings groupesMembre ou groupesSuivis
     * @param {callbackPersonne} next
     */
    function removeGroup (context, nom, groupTypes, next) {
      loadCurrentUser(context, function (error, me) {
        if (error) return next(error)
        let hasChanged = false
        groupTypes.forEach(prop => {
          // shortcut aucun groupe
          if (!me[prop] || !me[prop].length) return
          const newGroupes = me[prop].filter((groupeNom) => groupeNom !== nom)
          if (newGroupes.length === me[prop].length) return
          hasChanged = true
          me[prop] = newGroupes
        })
        if (hasChanged) saveCurrentUser(context, me, next)
        else next(new Error(`Vous n’étiez pas dans le groupe ${nom}`))
      })
    }

    /**
     * Met a jour le user courant en session et bdd
     * @private
     * @param {Context} context
     * @param {Personne} me
     * @param {callbackPersonne} next
     */
    function saveCurrentUser (context, me, next) {
      $session.updateCurrentUser(context, me)
      $personneRepository.save(me, next)
    }

    // méthodes exportées

    /**
     * Ajoute gestionnairesNames au groupe (en allant chercher les noms en bdd)
     * @param {Context} context
     * @param {Groupe} groupe
     * @param {groupeCallback} next
     */
    function addGestionnairesNames (context, groupe, next) {
      flow().seq(function () {
        // on veut les noms des gestionnaires
        const gestionnaires = groupe.gestionnaires || []
        $personneRepository.loadByOids(gestionnaires, this)
      }).seq(function (personnes) {
        groupe.gestionnairesNames = personnes.map((p, i) => {
          if (p) return `${p.prenom} ${p.nom}`
          // il est pas ou plus en base, faut quand même renvoyer une string
          const oid = groupe.gestionnaires[i]
          log.dataError(Error(`Le gestionnaire ${oid} du groupe ${groupe.oid} n’existe plus`))
          return `${oid} inconnu`
        })
        next(null, groupe)
      }).catch(next)
    }

    /**
     * Renvoie true si c'est le même index de groupe (après passage du normalizer)
     * @param {string} nom1
     * @param {string} nom2
     * @return {boolean}
     */
    function areEquals (nom1, nom2) {
      if (typeof nom1 !== 'string' || typeof nom2 !== 'string') throw Error('paramètres invalides')
      return getNormalizedName(nom1) === getNormalizedName(nom2)
    }

    /**
     * Ajoute un groupe suivi pour l'utilisateur courant
     * @param {Context} context
     * @param {string} nom Nom du groupe
     * @param {callbackPersonne} next
     */
    function followGroup (context, nom, next) {
      addGroup(context, nom, suivis, next)
    }

    /**
     * Retire un groupe suivi pour l'utilisateur courant
     * @param {Context} context
     * @param {string} nom Nom du groupe
     * @param {callbackPersonne} next
     */
    function ignoreGroup (context, nom, next) {
      removeGroup(context, nom, suivis, next)
    }

    /**
     * Retourne true si on suit ce groupe
     * @param context
     * @param {string|Groupe} groupe Le groupe ou son nom
     * @returns {boolean}
     */
    function isFollowed (context, groupe) {
      const groupesSuivis = $accessControl.getCurrentUserGroupesSuivis(context)
      const nom = getNom(groupe)
      if (nom && groupesSuivis.length) return groupesSuivis.includes(nom)
      return false
    }

    /**
     * Retourne true si on est gestionnaire du groupe
     * @param context
     * @param {Groupe} groupe Le groupe (pas son nom)
     * @returns {boolean}
     */
    function isManaged (context, groupe) {
      if (!groupe || !groupe.gestionnaires) throw Error('groupe invalide')
      const oid = $accessControl.getCurrentUserOid(context)
      if (!oid) return false
      return groupe.gestionnaires.includes(oid)
    }

    /**
     * Retourne true si on est membre du groupe
     * @param {Context} context
     * @param {string|Groupe} groupe Le groupe ou son nom
     * @returns {boolean}
     */
    function isMemberOf (context, groupe) {
      const groupesMembre = $accessControl.getCurrentUserGroupesMembre(context)
      const nom = getNom(groupe)
      if (nom && groupesMembre.length) return groupesMembre.includes(nom)
      return false
    }

    /**
     * Ajoute un groupe (membre) à l'utilisateur courant
     * @param {Context} context
     * @param {string} nom Nom du groupe
     * @param {callbackPersonne} next
     */
    function joinGroup (context, nom, next) {
      addGroup(context, nom, membre, next)
    }

    /**
     * Ajoute le groupe à groupesMembre et groupesSuivis du user courant
     * @param {Context} context
     * @param {string} nom Le groupe
     * @param {callbackPersonne} next
     */
    function joinAndFollowGroup (context, nom, next) {
      addGroup(context, nom, both, next)
    }

    /**
     * Retire un groupe (membre) à l'utilisateur courant
     * @param {Context} context
     * @param {string} nom Nom du groupe
     * @param {callbackPersonne} next
     */
    function quitGroup (context, nom, next) {
      removeGroup(context, nom, membre, next)
    }

    return {
      addGestionnairesNames,
      areEquals,
      followGroup,
      ignoreGroup,
      isFollowed,
      isManaged,
      isMemberOf,
      joinGroup,
      joinAndFollowGroup,
      quitGroup
    }
  })
}