'use strict'
const Personne = require('../../constructors/Personne')
const { isObjectPlain } = require('sesajstools')
const { truePropertiesList } = require('sesajstools/utils/object')
const { getNormalizedName } = require('../lib/normalize')
/**
* Entity pour un user
* @entity EntityPersonne
* @typedef EntityPersonne
* @extends Entity
* @extends Personne
*/
module.exports = function (component) {
component.entity('EntityPersonne', function ($cachePersonne) {
const configRoles = lassi.settings.components.personne.roles
const EntityPersonne = this
/**
* Calcule et affecte les permissions d'une personne en fonction de ses rôles
* et des permissions données à chaque rôle en configuration
* @param {Object} roles La liste des rôles avec {role1: true}
* @returns {Object} avec les permissions en propriété (valeur true|false|undefined)
*/
function getPermissions (roles) {
const permissions = {}
Object.keys(roles).forEach(role => {
const hasRole = roles[role]
// on ajoute les permissions définies pour ce role en config
if (hasRole && configRoles[role]) {
// faut pas faire de merge, on pourrait écraser avec false
// une permission déjà accordée par un rôle précédent
Object.keys(configRoles[role]).forEach(permission => {
const hasPerm = configRoles[role][permission]
if (hasPerm) permissions[permission] = true
})
}
})
return permissions
}
EntityPersonne.construct(function (values) {
// on impose les permissions d'après les rôles définis en config
// faut du shallow copy pour pas modifier values.permissions
const data = { ...values }
if (values.roles) data.permissions = getPermissions(values.roles)
// avant d'appeler le constructeur
Personne.call(this, data)
})
EntityPersonne.validateJsonSchema({
type: 'object',
properties: {
oid: { type: 'string' },
pid: { type: 'string', pattern: '^[a-zA-Z0-9_-]+/[a-z0-9_-]+$' },
nom: { type: 'string' },
prenom: { type: 'string' },
email: { type: 'string' },
roles: { type: 'object' },
permissions: { type: 'object' },
groupesMembre: { type: 'array', items: { type: 'string' }, uniqueItems: true },
groupesSuivis: { type: 'array', items: { type: 'string' }, uniqueItems: true },
infos: { type: 'object' },
dateCreation: { instanceof: 'Date' },
// cette propriété n'est pas gérée ici, mais elle envoyé par sesalab-sso,
// en attendant d'avoir un wrapper dans $auth pour gérer le login on l'accepte
structures: { type: 'array' } // à priori des array de {oid: string, value: Object}
},
additionalProperties: false,
required: [
'nom',
'pid'
]
})
EntityPersonne.beforeStore = function (next) {
// recalculé d'après les roles à chaque create/load (dans le constructeur),
// mais on le fait aussi ici pour le garantir avant persistance (pas grave) mais surtout mise en cache
// le faire 2 fois garanti d'avoir un db ok (avec la conf au moment de la sauvegarde)
// ET des permissions ok au runtime (au cas où la conf change)
if (this.roles) this.permissions = getPermissions(this.roles)
// @todo ajouter ici un checkAuthSource
if (!this.pid) throw new Error('personne sans pid, impossible à sauvegarder')
next()
}
EntityPersonne.afterStore(function (next) {
// on met en cache, attention à mettre la session à jour si besoin (pas de contexte ici)
$cachePersonne.set(this, function (error) {
if (error) log.error(error)
})
// et on passe au suivant sans se préoccuper du retour de mise en cache
next()
})
EntityPersonne
.defineIndex('pid')
.defineIndex('nom')
.defineIndex('email')
// par défaut, la valeur de l'index est la valeur du champ, mais on peut fournir
// une callback qui renvoie la valeur (ou un tableau de valeurs)
.defineIndex('roles', 'string', function () {
if (!isObjectPlain(this.roles)) return null
const roles = truePropertiesList(this.roles)
if (!roles.length) return null
return roles
})
.defineIndex('groupesMembre', { normalizer: getNormalizedName }, function () {
if (!this.groupesMembre || !this.groupesMembre.length) return null
return this.groupesMembre
})
.defineIndex('groupesSuivis', { normalizer: getNormalizedName }, function () {
if (!this.groupesSuivis || !this.groupesSuivis.length) return null
return this.groupesSuivis
})
})
}