Si vous publiez votre offre de formation depuis un dispositif de saisie ODF-Web vers un portail ODF, un bug faisait que les liens vers les pages internes du dispositif de saisie ne fonctionnait pas sur le portail : https://issues.ametys.org/browse/ODF-1297
Pour corriger cela, vous devez modifier les fichiers WEB-INF/param/workflow-program.xmlde vos applications ODF-Web(attention, les applications ODF seul ne doivent pas être modifiées).
Dans ces fichiers recherchez et remplacez org.ametys.odf.cdmfr.SendCDMFRFunction par org.ametys.plugins.odfweb.workflow.SendCDMFRFunction
Duplication d'un catalogue
Afin de corriger le bug https://issues.ametys.org/browse/ODF-1314, vous devez modifier le fichier de workflow WEB-INF/param/workflow-program.xml en ajoutant l'action suivante dans la section <initial-actions>
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
Dépublier une formation depuis un dispositif de saisie ODF non web
Cette section concerne uniquement les dispositifs de saisie ODF non Web, c'est à dire, n'utilisant pas le plugin ODF-Web
Une action de workflow de dépublication d'une formation a été ajoutée afin de pouvoir dépublier une formation publiée sur un portail ODF. Cette nouvelle action n'a de sens que si le dispositif de saisie publie ses formations sur un portail ODF. Il est cependant nécessaire de suivre les étapes suivantes dans tous les cas :
1) Ajoutez le droit dépublication
Dans le fichier WEB-INF/param/rights.xml, ajoutez le droit Workflow_Rights_Unpublish
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
Ajoutez les traductions du libellé et de la description du droit dans les fichiers WEB-INF/i18n/application.xml et WEB-INF/i18n/application_en.xml
application.xml
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
<message key="APPLICATION_RIGHTS_UNPUBLISH_LABEL">Dépublication</message>
<message key="APPLICATION_RIGHTS_UNPUBLISH_DESCRIPTION">Autorise à dépublier un contenu</message>
<message key="APPLICATION_RIGHTS_UNPUBLISH_LABEL">Dépublication</message>
<message key="APPLICATION_RIGHTS_UNPUBLISH_DESCRIPTION">Autorise à dépublier un contenu</message>
<message key="APPLICATION_RIGHTS_UNPUBLISH_LABEL">Dépublication</message>
<message key="APPLICATION_RIGHTS_UNPUBLISH_DESCRIPTION">Autorise à dépublier un contenu</message>
application_en.xml
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
<message key="APPLICATION_RIGHTS_UNPUBLISH_LABEL">Unpublish</message>
<message key="APPLICATION_RIGHTS_UNPUBLISH_DESCRIPTION">Allow unpublish action on contents</message>
<message key="APPLICATION_RIGHTS_UNPUBLISH_LABEL">Unpublish</message>
<message key="APPLICATION_RIGHTS_UNPUBLISH_DESCRIPTION">Allow unpublish action on contents</message>
<message key="APPLICATION_RIGHTS_UNPUBLISH_LABEL">Unpublish</message>
<message key="APPLICATION_RIGHTS_UNPUBLISH_DESCRIPTION">Allow unpublish action on contents</message>
2) Ajoutez l'action de workflow
Ajoutez ensuite l'action de workflow n°10 permettant la dépublication d'une formation dans le fichier WEB-INF/param/workflow-program.xml L'action est disponible depuis les états brouillon, proposé ou validé.
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
Le bouton sera disponible si le contributeur a le droit de dépublication et que la formation a été validée au moins une fois.
Pensez à ajouter le droit de dépublication à vos contributeurs !
Dépublier une formation sur depuis un dispositif de saisie ODF-web
Cette section concerne uniquement les dispositifs de saisie ODF Web, qui publie leur offre de formation sur un portail. Si vous avez un dispositif de saisie ODF non web, vous devez suivre les indications du chapitre précédent
L'action de workflow de dépublication existe déjà sur les applications ODF-Web.
Si les formations sont publiées sur un portail, vous devez simplement rajouter une instructions dans le fichier de workflow afin de supprimer une formation sur le portail, suite à sa dépublication depuis le dispositif de saisie.
Pour cela, dans le fichier de workflow WEB-INF/param/workflow-program.xml du dispositif,rajoutez la post-fonction org.ametys.odf.cdmfr.DeleteRemoteProgramFunction à l'action de dépublication n°10
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
A partir de la version 2.6.0, les éléments pédagogiques doivent nécessairement appartenir à un catalogue, tout comme les formations.
Ainsi la duplication de catalogue duplique également les éléments pédagogiques (les éléments pédagogiques se sont plus partagés entre catalogue).
Ajout de la métadonnée "catalog" sur les ELPs
Le modèle des ELPs (ou UE) doit nécessairement contenir une métadonnée "catalog". Si vous avez surchargé le modèle des ELPs (type de contenu org.ametys.plugins.odf.Content.course), vous devez ajouter cette métadonnée.
Si vous utilisez le type de contenu standard pour les ELPs, passez à la section suivante.
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
Attention, n'ajoutez pas la référence à cette nouvelle métadonnée dans la vue d'édition. En effet le catalogue ne doit pas être modifier depuis le formulaire d'édition car il nécessite des vérifications.
Ajoutez la référence à cette métadonnée dans les vues "details", "index" et "main" en mode "view"
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
Ajout de l'action de workflow pour créer un ELP par copie
Pour pouvoir copier les ELPs lors de la duplication d'un catalogue de formation, modifiez le fichier de workflow WEB-INF/param/workflow-course.xml pour y ajouter l'action de création par copie dans la section <initial-actions>
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
Exécutez le script suivant pour automatiquement positionner le nom du catalogue d'appartenance sur l'ensemble des ELPs. Le catalogue de l'ELP est récupéré à partir des formations d'appartenance.
Si un ELP est attaché à plusieurs formations de catalogues différents, un message d'erreur sera affiché. La migration doit alors se faire manuellement. Il sera nécessaire de supprimer l'ELP d'une ou une plusieurs formations de manière à ce que l'ELP n'appartienne qu'à des formations un seul et même catalogue. Vous pourrez alors ré-exécuter ce script.
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
var qm = session.getWorkspace().getQueryManager();
var getCatalogs = function (clContainer)
{
var parentNode = clContainer;
var catalog = null;
while (parentNode != null && catalog == null)
{
if (parentNode.getPrimaryNodeType().getName() == 'ametys:courseContent')
{
var query = qm.createQuery("//element(*, ametys:courseList)[@ametys:coursesReferences = 'courseContent://" + parentNode.getUUID() + "']", javax.jcr.query.Query.XPATH);
var clNodes = query.execute().getNodes();
var catalogs = [];
while (clNodes.hasNext())
{
var clCatalogs = getCatalogs(clNodes.next().getParent());
for (var i=0; i<clCatalogs.length; i++)
{
if (catalogs.indexOf(clCatalogs[i]) == -1)
{
catalogs.push(clCatalogs[i]);
}
}
}
return catalogs;
}
else if (parentNode.getPrimaryNodeType().getName() == 'ametys:programContent')
{
catalog = parentNode.getProperty("ametys:catalog").getString() + '';
}
else
{
parentNode = parentNode.getParent();
}
}
return catalog != null ? [catalog] : [];
}
var processCourse = function (course)
{
if (!course.hasProperty("ametys:catalog"))
{
var query = qm.createQuery("//element(*, ametys:courseList)[@ametys:coursesReferences = 'courseContent://" + course.getUUID() + "']", javax.jcr.query.Query.XPATH);
var clNodes = query.execute().getNodes();
var catalog = null;
while (clNodes.hasNext())
{
var clCatalogs = getCatalogs(clNodes.next().getParent());
if (catalog == null && clCatalogs.length == 1)
{
catalog = clCatalogs[0];
}
else if (clCatalogs.length > 1 || clCatalogs[0] != catalog)
{
var title = course.getProperty("ametys:title").getString();
var code = course.getProperty("ametys:elpCode").getString();
print("ERROR >> L'ELP " + title + " (" + code + ") est référencée par plusieurs listes appartenant à des catalogues différents => migration impossible");
catalog = null;
break;
}
}
if (catalog != null)
{
course.setProperty("ametys:catalog", catalog);
course.save();
return true;
}
}
return false;
}
// Default workspace
var query = qm.createQuery("//element(*, ametys:courseContent)[not(@ametys:catalog)]", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
var count = 0;
while (nodes.hasNext())
{
if (processCourse(nodes.next()))
{
count++;
}
}
print(count + " ELPs ont été mises à jour dans le workspace 'default'");
var qm = session.getWorkspace().getQueryManager();
var getCatalogs = function (clContainer)
{
var parentNode = clContainer;
var catalog = null;
while (parentNode != null && catalog == null)
{
if (parentNode.getPrimaryNodeType().getName() == 'ametys:courseContent')
{
var query = qm.createQuery("//element(*, ametys:courseList)[@ametys:coursesReferences = 'courseContent://" + parentNode.getUUID() + "']", javax.jcr.query.Query.XPATH);
var clNodes = query.execute().getNodes();
var catalogs = [];
while (clNodes.hasNext())
{
var clCatalogs = getCatalogs(clNodes.next().getParent());
for (var i=0; i<clCatalogs.length; i++)
{
if (catalogs.indexOf(clCatalogs[i]) == -1)
{
catalogs.push(clCatalogs[i]);
}
}
}
return catalogs;
}
else if (parentNode.getPrimaryNodeType().getName() == 'ametys:programContent')
{
catalog = parentNode.getProperty("ametys:catalog").getString() + '';
}
else
{
parentNode = parentNode.getParent();
}
}
return catalog != null ? [catalog] : [];
}
var processCourse = function (course)
{
if (!course.hasProperty("ametys:catalog"))
{
var query = qm.createQuery("//element(*, ametys:courseList)[@ametys:coursesReferences = 'courseContent://" + course.getUUID() + "']", javax.jcr.query.Query.XPATH);
var clNodes = query.execute().getNodes();
var catalog = null;
while (clNodes.hasNext())
{
var clCatalogs = getCatalogs(clNodes.next().getParent());
if (catalog == null && clCatalogs.length == 1)
{
catalog = clCatalogs[0];
}
else if (clCatalogs.length > 1 || clCatalogs[0] != catalog)
{
var title = course.getProperty("ametys:title").getString();
var code = course.getProperty("ametys:elpCode").getString();
print("ERROR >> L'ELP " + title + " (" + code + ") est référencée par plusieurs listes appartenant à des catalogues différents => migration impossible");
catalog = null;
break;
}
}
if (catalog != null)
{
course.setProperty("ametys:catalog", catalog);
course.save();
return true;
}
}
return false;
}
// Default workspace
var query = qm.createQuery("//element(*, ametys:courseContent)[not(@ametys:catalog)]", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
var count = 0;
while (nodes.hasNext())
{
if (processCourse(nodes.next()))
{
count++;
}
}
print(count + " ELPs ont été mises à jour dans le workspace 'default'");
var qm = session.getWorkspace().getQueryManager();
var getCatalogs = function (clContainer)
{
var parentNode = clContainer;
var catalog = null;
while (parentNode != null && catalog == null)
{
if (parentNode.getPrimaryNodeType().getName() == 'ametys:courseContent')
{
var query = qm.createQuery("//element(*, ametys:courseList)[@ametys:coursesReferences = 'courseContent://" + parentNode.getUUID() + "']", javax.jcr.query.Query.XPATH);
var clNodes = query.execute().getNodes();
var catalogs = [];
while (clNodes.hasNext())
{
var clCatalogs = getCatalogs(clNodes.next().getParent());
for (var i=0; i<clCatalogs.length; i++)
{
if (catalogs.indexOf(clCatalogs[i]) == -1)
{
catalogs.push(clCatalogs[i]);
}
}
}
return catalogs;
}
else if (parentNode.getPrimaryNodeType().getName() == 'ametys:programContent')
{
catalog = parentNode.getProperty("ametys:catalog").getString() + '';
}
else
{
parentNode = parentNode.getParent();
}
}
return catalog != null ? [catalog] : [];
}
var processCourse = function (course)
{
if (!course.hasProperty("ametys:catalog"))
{
var query = qm.createQuery("//element(*, ametys:courseList)[@ametys:coursesReferences = 'courseContent://" + course.getUUID() + "']", javax.jcr.query.Query.XPATH);
var clNodes = query.execute().getNodes();
var catalog = null;
while (clNodes.hasNext())
{
var clCatalogs = getCatalogs(clNodes.next().getParent());
if (catalog == null && clCatalogs.length == 1)
{
catalog = clCatalogs[0];
}
else if (clCatalogs.length > 1 || clCatalogs[0] != catalog)
{
var title = course.getProperty("ametys:title").getString();
var code = course.getProperty("ametys:elpCode").getString();
print("ERROR >> L'ELP " + title + " (" + code + ") est référencée par plusieurs listes appartenant à des catalogues différents => migration impossible");
catalog = null;
break;
}
}
if (catalog != null)
{
course.setProperty("ametys:catalog", catalog);
course.save();
return true;
}
}
return false;
}
// Default workspace
var query = qm.createQuery("//element(*, ametys:courseContent)[not(@ametys:catalog)]", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
var count = 0;
while (nodes.hasNext())
{
if (processCourse(nodes.next()))
{
count++;
}
}
print(count + " ELPs ont été mises à jour dans le workspace 'default'");
Après avoir exécuter le script, allez dans le back office et assurez-vous que toutes les ELPs sont dans l'état "Validé". Valider toutes les ELPs qui ne sont pas dans l'état validé !
Puis exécuter le script suivant afin de répercuter correctement les modifications pour le label "Live".
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:courseContent)", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
var count = 0;
while (nodes.hasNext())
{
var node = nodes.next();
node.checkin();
node.checkout();
var versionName = node.getBaseVersion().getName();
node.getVersionHistory().addVersionLabel(versionName, "Live", true);
count++;
}
print(count + " courses have been checkpoint");
var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:courseContent)", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
var count = 0;
while (nodes.hasNext())
{
var node = nodes.next();
node.checkin();
node.checkout();
var versionName = node.getBaseVersion().getName();
node.getVersionHistory().addVersionLabel(versionName, "Live", true);
count++;
}
print(count + " courses have been checkpoint");
var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:courseContent)", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
var count = 0;
while (nodes.hasNext())
{
var node = nodes.next();
node.checkin();
node.checkout();
var versionName = node.getBaseVersion().getName();
node.getVersionHistory().addVersionLabel(versionName, "Live", true);
count++;
}
print(count + " courses have been checkpoint");
Ajout du critère et de la colonne résultat "Catalogue" sur l'outil de recherche des ELPs
Si vous avez surchargé le modèle de recherche BO sur les éléments pédagogiques, vous devez ajouter le critère de recherche "Catalogue" ainsi que la colonne résultat.
Si vous utilisez le moteur de recherche standard, passez à la section suivante.
Définition du critère et colonne de recherche
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
Lors d'un import de formation depuis un flux XML CDM-fr, les règles suivantes sont appliquées :
si le catalogue n'est pas présent ou vide dans le CDM-fr, l'ELP est directement affecté au catalogue de la formation importée ou synchronisée
si le catalogue est non vide,
et qu'il est identique à celui de la formation importée, l'ELP est importée ou synchronisé
et qu'il est différent de celui de la formation importée, une erreur est levée et l'ELP n'est ni importée ni synchronisé
A noter que si vous êtes dans un mode de synchronisation "remote" (Portail), et que vous avez forcé le catalogue d'import dans les paramètres de configuration, la valeur contenu dans le CDM-fr sera ignorée. Les formations et les ELPs seront automatiquement affecté au catalogue défini dans le paramètre de configuration.