/**
* This file is part of Sesatheque.
* Copyright 2014-2015, Association Sésamath
*
* Sesatheque is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3
* as published by the Free Software Foundation.
*
* Sesatheque is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Sesatheque (LICENCE.txt).
* @see http://www.gnu.org/licenses/agpl.txt
*
*
* Ce fichier fait partie de l'application Sésathèque, créée par l'association Sésamath.
*
* Sésathèque est un logiciel libre ; vous pouvez le redistribuer ou le modifier suivant
* les termes de la GNU Affero General Public License version 3 telle que publiée par la
* Free Software Foundation.
* Sésathèque est distribué dans l'espoir qu'il sera utile, mais SANS AUCUNE GARANTIE,
* sans même la garantie tacite de QUALITÉ MARCHANDE ou d'ADÉQUATION à UN BUT PARTICULIER.
* Consultez la GNU Affero General Public License pour plus de détails.
* Vous devez avoir reçu une copie de la GNU General Public License en même temps que Sésathèque
* (cf LICENCE.txt et http://vvlibri.org/fr/Analyse/gnu-affero-general-public-license-v3-analyse
* pour une explication en français)
*/
'use strict'
import { getBaseUrl, getRidComponents } from '../sesatheques'
import Ref from './Ref'
import { constantes } from '../config'
import tools from 'sesajstools'
const { hasProp } = tools
/**
* Définition d'un ClientItem. C'est une Ressource avec des attributs en moins
* (idem Ref où aliasOf est remplacé par rid)
* et d'autres volatiles en plus ($droits et les $xxxUrl).
* Il est à priori construit coté client, ce n'est pas une entité
* @param {Object} [values={}] L'objet qui sert à initialiser un nouvel objet Ref, accepte une Ressource
* @throws {Error} Si on passe des enfants sur un type non arbre
* @constructor
*/
export default function ClientItem (values) {
if (typeof values !== 'object') values = {}
// on commence par initialiser avec une ref
Object.assign(this, new Ref(values))
// les erreurs sont un type particulier minimaliste auquel on ajoute rien
if (this.type === 'error') return { type: 'error', titre: this.titre }
// idem Ref où aliasOf est remplacé par rid
// le constructeur Ref se charge d'init aliasRid ou pas
/**
* Rid de la ressource qu'on représente
*/
this.rid = this.aliasOf
delete this.aliasOf
// pour la doc faut ajouter tout ça
/**
* Rid de l'alias éventuel que l'on représente
* @property aliasRid
* @type {string}
*/
/**
* Titre
* @property titre
* @type {string}
*/
/**
* Résumé (pour tous)
* @property resume
* @type {string}
*/
/**
* Description (pour tous)
* @property description
* @type {string}
*/
/**
* Commentaires (pour le formateur)
* @property commentaires
* @type {string}
*/
/**
* Le type qui permet de savoir à quel type de contenu s'attendre, ou quel picto afficher
* @property type
* @type {string}
*/
/**
* Un ou des id de catégorie(s) éventuel (pour un picto)
* @property categories
* @type {number[]}
*/
/**
* True si public (sinon il faut être authentifié pour lire la ressource)
* @property public
* @type {boolean}
*/
/**
* Éventuelle clé de lecture, pour que des élèves puissent lire
* la ressource non publique si leur prof la leur affecte
* @property cle
* @type {string}
*/
/**
* true si la ressource privée est partagée avec un ou des groupes
* @property partage
* @type {boolean}
* @default undefined
*/
/**
* Un incrément ajouté à l'url pour contourner le cache du navigateur en cas de modif
* @property inc
* @type number
*/
// on passe aux routes
// si on est issu d'un alias, on a rid (la ressource) et aliasRid (l'alias),
// dans ce cas c'est l'original qui nous intéresse,
// sauf pour le delete où on veut effacer l'alias
// attention, on peut être un item sans rid (qui n'a pas de ressource équivalente,
// un simple dossier dans un arbre)
if (this.rid) {
// => on a des urls à mettre
const [originalBaseId, oid] = getRidComponents(this.rid)
const originalBaseUrl = getBaseUrl(originalBaseId)
const publicSuffix = this.inc ? `?inc=${this.inc}` : ''
const { describe, display, edit } = constantes.routes
// $displayUrl et $describeUrl
if (this.public) {
/**
* Url absolue pour afficher la ressource
* @type {string}
*/
this.$displayUrl = `${originalBaseUrl}public/${display}/${oid}${publicSuffix}`
/**
* Url absolue de description de la ressource
* @type {string}
*/
this.$describeUrl = `${originalBaseUrl}ressource/${describe}/${oid}${publicSuffix}`
} else if (values.cle) {
this.$displayUrl = `${originalBaseUrl}public/${display}/cle/${values.cle}${publicSuffix}`
// pas de clé pour describe, un élève se prendra une 403 (mais il devrait pas avoir le lien)
// (idem pour un prof qui n'aurait pas les droits)
this.$describeUrl = `${originalBaseUrl}ressource/${describe}/${oid}`
} else {
// privée sans clé de lecture, un utilisateur élève se prendrait une 404,
// mais ça ne devrait pas arriver car la clé est générée au beforeStore
// On laisse pour le cas où la ressource viendrait de passer privée
// et n'aurait pas encore été sauvegardée.
this.$displayUrl = `${originalBaseUrl}ressource/${display}/${oid}`
this.$describeUrl = `${originalBaseUrl}ressource/${describe}/${oid}`
}
// $dataUrl
if (this.public) {
/**
* Url absolue du json de la ressource
* @type {string}
*/
this.$dataUrl = `${originalBaseUrl}api/public/${oid}${publicSuffix}`
} else {
this.$dataUrl = `${originalBaseUrl}api/ressource/${oid}`
}
if (values.$droits) {
// $editUrl
if (values.$droits.includes('W')) {
let editBaseUrl
let editId
if (values.aliasRid) {
// c'est une ressource alias, avec aliasOf ET aliasRid, effacement et édition concerne l'alias
// (il sera cloné par la sésathèque à la 1re édition pour devenir une ressource à part entière)
const [aliasBaseId, aliasId] = getRidComponents(values.aliasRid)
editBaseUrl = getBaseUrl(aliasBaseId)
editId = aliasId
} else {
editBaseUrl = originalBaseUrl
editId = oid
}
/**
* Url absolue d'édition (propriété présente quand on sait que l'utilisateur courant a les droits)
* @type {string}
*/
this.$editUrl = `${editBaseUrl}ressource/${edit}/${editId}`
// $deleteUrl n'existe jamais sans $editUrl, on récupère donc la base du dessus
if (values.$droits.includes('D')) {
/**
* Url absolue de suppression via l'api (si l'utilisateur courant a les droits de suppression)
* propriété absente si on en sait rien
* @type {string}
*/
this.$deleteUrlApi = `${editBaseUrl}api/ressource/${editId}`
}
}
}
} else if (this.type !== 'arbre') {
// aliasOf est obligatoire, sauf pour error (éliminé au départ) et arbre
// (dans ce cas cet item est un simple dossier et pas une ressource)
throw Error('Ressource invalide')
}
// reste les éventuels enfants que l'on normalise aussi comme ClientItem[]
if (Array.isArray(this.enfants)) {
/**
* Liste des enfants (tous normalisés)
* @type {ClientItem[]}
*/
if (this.enfants.length) this.enfants = this.enfants.map(e => new ClientItem(e))
} else if (hasProp(this, 'enfants')) {
console.error(`propriété enfants invalide pour ${this.rid}`, this.enfants)
delete this.enfants
}
// Pour les paramètres, on laisse le constructeur de Ref décider
/**
* Les paramètres éventuels (à priori pour le type sequenceModele),
* forcément un plain Object s'il existe
* @property parametres
* @type {Object}
*/
}
/**
* Cast en string d'une ref (son titre avec aliasOf)
* @returns {string}
*/
ClientItem.prototype.toString = function () {
if (this.aliasRid) return `${this.titre} (${this.rid} => ${this.aliasRid})`
return `${this.titre} (${this.rid})`
}