Manuel de migration technique des versions 1.1.x, 1.2.x et 1.3.x vers 2.x


  1. Modèle de données
    1. Nouveaux champs énumérés
    2. Domaine et domaine ministériel
    3. Metadonnée "universalAdjustment"
    4. Suppression du "secteur d'activité"
    5. Suppression de la "discipline"
    6. Lieux multi-valués
    7. Pièces jointes multiples
    8. Texte riche synchronisé
    9. Mots clés d'un sous-programme multi-valués
    10. Établissements cohabilités devient un champ énumérés
    11. Composante
      1. le code RNE devient code UAI
      2. Changement du nom de la composante racine
  2. Service "Liste de formations"
    1. Migration des données
    2. Migration de la charte graphique
  3. Service de recherche
    1. Migration des données
    2. Migration de la charte graphique
  4. Service "insérer un contenu"
  5. Fichiers SQLMap pour Apogée
  6. Fichiers de conversion Apogée
  7. Fichier runtime.xml
  8. Fichier de ribbon
  9. Workflow

Modèle de données

Nouveaux champs énumérés

Les référenciels ROME, SISE, ERASMUS et CITE 97 deviennent des champs énumérées.

Le champ "Secteur disciplinaire DGESIP" a été ajouté. Il s'agit d'un champ énuméré multiple.

Certains valeurs et libellés de champs énumérés existants (Diplôme, Niveau d'étude, Nature du diplômes, etc, ...) ont également été modifiés.

Téléchargez  les fichiers xml de ces champs énumérés et les copier/remplacer dans le répertoire WEB-INF/param/odf de votre application.

Ajoutez/remplacez les clés i18n associées  dans votre catalogue application (WEB-INF/i18n/application.xml et WEB-INF/i18n/application_en.xml).

Exécutez dans la console les différents scripts de migrations : Migration des champs énumérés v1 vers v2

Domaine et domaine ministériel

Le domaine ministériel devient un champ énuméré et devient obligatoire.

Ce champ est désormais utilisé pour construire l'arborescence virtuelle à la place du champ "Domaine discipline".

Téléchargez le fichier xml  domain.xml et le copier dans le répertoire WEB-INF/param/odf de votre application.

Ajoutez les clés i18n associées dans votre catalogue application (WEB-INF/i18n/application.xml et WEB-INF/i18n/application_en.xml):

<message key="APPLICATION_ODF_PRIMARY_DOMAIN_00">Hors domaines de formation</message>
<message key="APPLICATION_ODF_PRIMARY_DOMAIN_01">Arts, Lettres, Langues</message>
<message key="APPLICATION_ODF_PRIMARY_DOMAIN_02">Droit, Economie, Gestion</message>
<message key="APPLICATION_ODF_PRIMARY_DOMAIN_03">Sciences humaines et sociales</message>
<message key="APPLICATION_ODF_PRIMARY_DOMAIN_04">Sciences, Technologies, Santé</message>
<message key="APPLICATION_ODF_PRIMARY_DOMAIN_05">Sciences et technologies des activités physiques et sportives</message>

La métadonnée "ministryDomain" a été supprimée. Si vous avez surchargé la définition des contenus program et/ou subprogram (WEB-INF/param/content-types/_override/*.xml), vous devez supprimer toutes les références à "ministryDomain"

La métadonnée "ametys:domain" est toujours utilisée pour l'arborescence et les différents services ODF, mais elle ne correspond plus aux domaines définis dans le fichier domain_discipline.xml mais au nouveaux fichier domain.xml.
Exécuter le script suivant pour migrer le champ domaine de vos formations ne pas perdre l'arborescence de l'offre de formation.

Attention, les codes des "domaines" existants dépends de votre application. Reportez-vous à votre fichier pour faire la correspondance.

var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:defaultContent)[@ametys-internal:contentType = 'org.ametys.plugins.odf.Content.program']", javax.jcr.query.Query.XPATH); 

var nodes = query.execute().getNodes();
 
var count = 0;
while (nodes.hasNext())
{
   var program = nodes.next();
  
   if (program.hasProperty("ametys:domain"))
   {
     var domain = program.getProperty("ametys:domain").getValue().getString();
     if (domain == "0001")
     {
       // Sciences humaines et sociales
       program.setProperty("ametys:domain", "SHS"); 
     }
     else if (domain == "0002")
     {
       // Droit, Economie, Gestion
       program.setProperty("ametys:domain", "DEG");
     }
     else if (domain == "0003")
     {
       // Arts, Lettres, Langues
       program.setProperty("ametys:domain", "ALL");
     }
     else if (domain == "0004")
     {
       // Sciences, Technologies, Santé
       program.setProperty("ametys:domain", "STS");
     }
     program.save();
     count++;
   }
}

println(count + " programs has been modified");

Metadonnée "universalAdjustment"

La métadonnée "universalAdjustment" correspondant au champ "aménagements particuliers", était parfois mal nommée "universalAdjustement".

Si vous avez surchargé la définition des contenus program, subprogram et/ou orgunit (WEB-INF/param/content-types/_override/*.xml), vous devez replacer toutes les références à "universalAdjustement" par "universalAdjustment"

Pour vos données, executez le script suivant:

var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:defaultContent)[@ametys-internal:contentType = 'org.ametys.plugins.odf.Content.program' or @ametys-internal:contentType = 'org.ametys.plugins.odf.Content.subProgram' or @ametys-internal:contentType = 'org.ametys.plugins.odf.Content.orgunit']", javax.jcr.query.Query.XPATH);
 
var nodes = query.execute().getNodes();
  
var count = 0;
while (nodes.hasNext())
{
   var node = nodes.next();
   if (node.hasNode("ametys:universalAdjustement_remote"))
   {
        var uaNode = node.getNode("ametys:universalAdjustement_remote");
        uaNode.getSession().move(uaNode.getPath(), node.getPath() + "/ametys:universalAdjustment_remote");
        
        node.save(); 
        count++;
   }
   if (node.hasNode("ametys:universalAdjustement"))
   {
        var uaNode = node.getNode("ametys:universalAdjustement");
        uaNode.getSession().move(uaNode.getPath(), node.getPath() + "/ametys:universalAdjustment");
        
        node.save(); 
        count++;
   }
}

println(count + " contents have been modified");

Suppression du "secteur d'activité"

Le champs "secteur d'activité" a été supprimé au profit du champ "Secteur DGESIP".

  • Si vous souhaitez conserver ce champ vous devrez redéfinir la métadonnée "sector_activity" dans le fichier WEB-INF/param/content-types/_override/org.ametys.plugins.odf.Content.program.xml
<cms:metadata name="sector-activity" type="string" multiple="true">
        <label i18n="true">plugin.odf-projet:PLUGINS_ODF_PROJET_SECTOR_ACTIVITY</label>
        <description i18n="true">plugin.odf-projet:PLUGINS_ODF_PROJET_SECTOR_ACTIVITY_DESC</description>
        <widget>sorted-multiselect</widget>
        <enumeration>
            <custom-enumerator class="org.ametys.plugins.odfprojet.enumeration.SectorsEnumerator"/>
        </enumeration>   
</cms:metadata>

Attention, la classe SectorsEnumerator n'existe plus dans le plugin ODF, il faudra la écrire

 

  • Si vous ne souhaitez pas conserver ce champ, vous supprimez le fichier WEB-INF/param/odf/sector_activity.xml et supprimer toutes les références à la métadonnée "sector_activity" dans le fichier WEB-INF/param/content-types/_override/org.ametys.plugins.odf.Content.program.xml (si vous avez surcharger le modèle de données d'une formation)

Suppression de la "discipline"

Le champs "discipline" a été supprimé au profit du champ "Discipline SISE".

  • Supprimer le fichier WEB-INF/param/odf/domain_discipline.xml
  • Remplacer toutes les références à la métadonnée "domain_discipline" par la métadonnée "siseCode" dans le fichier WEB-INF/param/content-types/_override/org.ametys.plugins.odf.Content.program.xml (si vous avez surcharger le modèle de données d'une formation)
  • Executez le script suivant pour migrer vos formations:
importClass(org.ametys.workspaces.repository.ConsoleHelper);

var mapping = {
    '0001.1': '27', // Histoire
    '0001.2': '27', // Géographie
    '0001.3': '29', // Aménagement
    '0001.4': '32', // Psychologie
    '0001.5': '33', // Sociologie, démographie
    '0001.6': '34', // Sciences de l'éducation
    '0001.7': '35', // Sciences de l'info. et de la communication
    '0001.8': '66', // Pluri Sciences humaines et Sociales
    '0002.1': '36', // Sciences juridiques
    '0002.2': '37', // Sciences politiques
    '0002.3': '38', // Sciences économiques
    '0002.4': '39', // Sciences de gestion
    '0002.5': '40', // Administration économique et sociale
    '0002.6': '62', // Pluri Sciences Economique-Gestion
    '0003.1': '17',	// Sciences du langage - linguistique
    '0003.2': '18', // Langues et littératures anciennes
    '0003.3': '19', // Langues et littératures françaises
    '0003.4': '20', // Littérature générale et comparée
    '0003.5': '22', // Français, langue étrangère
    '0003.6': '23', // Langues et littératures étrangères
    '0003.7': '24', // Langues étrangères appliquées
    '0003.8': '25', // Cultures et langues régionales
    '0003.9': '67', // Pluri Lettres-Langues-Sciences humaines
    '0004.1': '1',  // Mathématique
    '0004.2': '2', 	// Physique
    '0004.3': '3',  // Chimie
    '0004.4': '4',  // Mathématiques appliquées - sciences sociales
    '0004.5': '5',  // Sciences de l'univers
    '0004.6': '6',  // Sciences de la vie
    '0004.7': '11', // Mécanique, génie mécanique
    '0004.8': '12', // Génie civil
    '0004.9': '13', // Génie des procédés
    '0004.10': '14', // Informatique
    '0004.11': '15', // Electronique, génie électrique
	'0004.12': '16', // Sciences et technologie industrielles
	'0004.13': '41', // Form. générale métiers de l'ingénieur
	'0004.14': '43', // Physique et Chimie
	'0004.15': '68', // Pluri Sciences Fondamentales et Application
	'0004.16': '70', // Pluri Sciences
	'0004.17': '7',  // Médecine
	'0004.18': '9',  // Pharmacie
	'0004.19': '69', // Pluri Sciences de la vie,de la santé
	'0004.20': '71'  // Pluri Santé 
}

var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:defaultContent)[@ametys-internal:contentType = 'org.ametys.plugins.odf.Content.program']", javax.jcr.query.Query.XPATH); 

var nodes = query.execute().getNodes();
 
var count = 0;
while (nodes.hasNext())
{
   	var program = nodes.next();
  	var needSave = false;
   	if (program.hasProperty("ametys:domain-discipline"))
   	{	
		var newValues = [];
		var oldValues = program.getProperty("ametys:domain-discipline").getValues();
		for (var i=0; i < oldValues.length; i++)
		{
	 		var oldValue= oldValues[i].getString();
			if (mapping[oldValue] != null)
			{
				newValues.push(mapping[oldValue]);
     		}
		}
		if (newValues.length != 0)
		{
			var siseCodes = java.lang.reflect.Array.newInstance(java.lang.String, newValues.length);
           	ConsoleHelper.setProperty(program, "ametys:siseCode", siseCodes);
		}
		program.getProperty("ametys:domain-discipline").remove();
		needSave = true;
	}
	
	if (program.hasProperty("ametys:domain-discipline_remote"))
   	{	
		var newValues = [];
		var oldValues = program.getProperty("ametys:domain-discipline_remote").getValues();
		for (var i=0; i < oldValues.length; i++)
		{
	 		var oldValue= oldValues[i].getString();
			if (mapping[oldValue] != null)
			{
				newValues.push(mapping[oldValue]);
     		}
		}
		if (newValues.length != 0)
		{
			var siseCodes = java.lang.reflect.Array.newInstance(java.lang.String, newValues.length);
           	ConsoleHelper.setProperty(program, "ametys:siseCode_remote", siseCodes);
		}
		program.getProperty("ametys:domain-discipline_remote").remove();
		needSave = true;
	}

	if (program.hasProperty("ametys:domain-discipline_sync"))
   	{
		var sync = program.getProperty("domain-discipline_sync").getValue().getBoolean(); 
		program.setProperty("ametys:siseCode_sync", sync);
		program.getProperty("ametys:domain-discipline_sync").remove();	
       	needSave = true;
	}

	if (needSave)
	{
   		program.save();
   		count++;
	}
}

println(count + " programs has been modified");

Lieux multi-valués

importClass(org.ametys.workspaces.repository.ConsoleHelper);

function _migrateMultipleMetadata (node, propertyName)
{
    if (node.hasProperty(propertyName))
    {
       var property = node.getProperty(propertyName);
       if (!property.getDefinition().isMultiple())
       {
           var value = property.getValue().getString();
           property.remove();
             
           var values = value.split(",");
           var places = java.lang.reflect.Array.newInstance(java.lang.String, values.length);
           for (var i=0; i < values.length; i++)
           {
               places[i] = values[i].trim();
           }
           ConsoleHelper.setProperty(node, propertyName, places);
           node.save();
           return true;
       }        
    }
    return false;
}

var query1 = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:defaultContent)[@ametys-internal:contentType = 'org.ametys.plugins.odf.Content.program' or @ametys-internal:contentType = 'org.ametys.plugins.odf.Content.subProgram']", javax.jcr.query.Query.XPATH);
  
var programNodes= query1.execute().getNodes();
   
var count = 0;
while (programNodes.hasNext())
{
   var node = programNodes.next();
   if (_migrateMultipleMetadata (node, "ametys:place") || _migrateMultipleMetadata (node, "ametys:place_remote"))
   {
   		count++;       
   }
}
println(count + " programs have been modified");

var query2 = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:defaultContent)[@ametys-internal:contentType = 'org.ametys.plugins.odf.Content.course']", javax.jcr.query.Query.XPATH);
  
var courseNodes = query2.execute().getNodes();
   
var count = 0;
while (courseNodes.hasNext())
{
   var node = courseNodes.next();
   if (_migrateMultipleMetadata (node, "ametys:teachingLocation") || _migrateMultipleMetadata (node, "ametys:teachingLocation_remote"))
   {
   		count++;       
   }
}
println(count + " courses' place have been modified");

 

Pièces jointes multiples

Les fichiers à télécharger sur une formation deviennent multiple.

Executez le script suivant pour migrer les pièces jointes existantes:

var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:defaultContent)[@ametys-internal:contentType = 'org.ametys.plugins.odf.Content.program']", javax.jcr.query.Query.XPATH);
 
var nodes = query.execute().getNodes();
  
var count = 0;
while (nodes.hasNext())
{
   var program = nodes.next();
  
   if (program.hasNode("ametys:attachment") && !program.hasNode("ametys:attachments"))
   {
       var attachNode = program.getNode("ametys:attachment");
       var entryNode = program.addNode("ametys:attachments", "ametys:compositeMetadata").addNode("ametys:1", "ametys:compositeMetadata");
       // Move node
       attachNode.getSession().move(attachNode.getPath(), entryNode.getPath() + "/ametys:attachment");
     
       program.save();
       count++;
   } 
}

println(count + " attachments have been moved");

Si vous avez surchargé la définition des contenus "program" (WEB-INF/param/content-types/_override/*.xml), pensez à modifier les références à la métadonnée "ametys:attachment" qui devient:

<cms:metadata-ref name="attachments">
    <cms:metadata-ref name="attachment"/>
    <cms:metadata-ref name="attachment-text"/>
</cms:metadata-ref>       

Texte riche synchronisé

Les métadonnées de l'ODF de type texte riche ne stockent plus les données synchronisées (remote) en tant que texte simple. Elles sont dorénavant sotckées en tant que texte riche.

Pour prendre en compte ce changement, le script suivant doit être executé :

importClass(java.io.ByteArrayInputStream);
importClass(org.ametys.plugins.repository.RepositoryConstants);

var data = {
	'ametys:courseContent' : [
		'description',
		'objectives',
		'neededPrerequisite',
		'recommendedPrerequisite',
		'formOfAssessment',
		'benefits',
		'syllabus',
		'additionalInformations'
	],
	'ametys:programContent' : [
		'presentation',
		'objectives',
		'qualification',
		'teachingOrganization',
		'accessCondition',
		'neededPrerequisite',
		'recommendedPrerequisite',
		'furtherStudy',
		'studyAbroad',
		'targetGroup',
		'jobOpportunities',
		'trainingStrategy',
		'knowledgeCheck',
		'universalAdjustment',
		'additionalInformations',
		'reorientation',
		'expenses'
	],
	'ametys:subProgramContent' : [
		'presentation',
		'objectives',
		'qualification',
		'teachingOrganization',
		'accessCondition',
		'neededPrerequisite',
		'recommendedPrerequisite',
		'furtherStudy',
		'studyAbroad',
		'targetGroup',
		'jobOpportunities',
		'trainingStrategy',
		'knowledgeCheck',
		'universalAdjustment',
		'additionalInformations',
		'reorientation',
		'expenses'
	],
	'ametys:orgunitContent' : [
		'description',
		'admissionInfo',
		'regulations',
		'expenses',
		'universalAdjustment',
		'studentFacilities',
		'additionalInfos'
	],
	'ametys:personContent' : [
		'additionalInformations'
	]
};

var qm = session.getWorkspace().getQueryManager();
	suffix = '_remote',
	count = 0;

for (var nt in data) {

	var query = qm.createQuery('//ametys:odf//element(*, ' + nt + ')', javax.jcr.query.Query.XPATH);
		nodes = query.execute().getNodes(),
		props = data[nt],
		l = props.length;

	while (nodes.hasNext()) {
		var contentNode = nodes.next();
        if (contentNode.isLocked()) unlock(contentNode);
      
		for (var i = 0; i < l; i++) {
			if (convertToRichText(contentNode, props[i] + suffix)) {
				count++;
			}
		}
	}
}

function unlock(node)
{
    if (!node) return;
  
    var lm = node.getSession().getWorkspace().getLockManager();
    if (lm.holdsLock(node.getPath()))
    {
      var lockToken = node.getProperty(RepositoryConstants.METADATA_LOCKTOKEN).getString();
     
      lm.addLockToken(lockToken);
      lm.unlock(node.getPath());
     
      // Remove residual properties
      node["setProperty(java.lang.String,javax.jcr.Value)"](RepositoryConstants.METADATA_LOCKTOKEN, null);
      node["setProperty(java.lang.String,javax.jcr.Value)"](RepositoryConstants.METADATA_LOCKOWNER, null);
    }
    else
    {
      unlock(node.getParent());
    }
}

function convertToRichText(contentNode, metadataName) {
	var prefix = 'ametys:',
		fullMetadataName = prefix + metadataName;
		
	function strToIS(str) {
        var bytes = new java.lang.String(str).getBytes('UTF-8');
		return new ByteArrayInputStream(bytes);
	}
	
	function setInputStream(rtNode, stream) {
		var binary = rtNode.getSession().getValueFactory().createBinary(stream);
		rtNode.setProperty('jcr:data', binary);
	}
	
	function setMimeType(rtNode, mime) {
		rtNode.setProperty('jcr:mimeType', mime);
	}

	if (contentNode.hasProperty(fullMetadataName)) {
		var p = contentNode.getProperty(fullMetadataName);
		var str = p.getString();
		
		if (!contentNode.hasNode(fullMetadataName)) {
			if (str) {
				var rtn = contentNode.addNode(fullMetadataName, prefix + 'richText'),
					db = textToDocbook(str);
				setInputStream(rtn, strToIS(db));
				setMimeType(rtn, 'text/xml');
			}
			
			p.remove();
			return true;
		}
		else {
			prinln('node ' + contentNode.getPath() + ' has a property and a node with the the name ' + fullMetadataName);
		}
	}
	return false;
}

function textToDocbook(str) {
	var mapping = {
		'<' : '&lt;',
		'&' : '&amp;',
		'\r\n' : '<phrase role="linebreak"/>',
		'\n' : '<phrase role="linebreak"/>'
	};
	
	function repFn(match, p1) {
		return mapping[p1];
	}

	var res = '';
	res +=  '<?xml version="1.0" encoding="UTF-8"?>';
	res +=  '<article xmlns="http://docbook.org/ns/docbook">';
	res +=      '<para>';
	res +=          new String(str).replace(/(<|&|\r?\n)/g, repFn);
	res +=      '</para>';
	res +=  '</article>';

	return res;
}

session.save();
println(count + ' metadata migrated');

Mots clés d'un sous-programme multi-valués

Les mots clés d'un sous-programme sont maintenant multi-valués. Executez le script suivant pour migrer vos sous-programmes:

importClass(org.ametys.workspaces.repository.ConsoleHelper);

var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:defaultContent)[@ametys-internal:contentType = 'org.ametys.plugins.odf.Content.subProgram']", javax.jcr.query.Query.XPATH);
 
var nodes = query.execute().getNodes();
  
var count = 0;
while (nodes.hasNext())
{
   var node = nodes.next();
   
   if (node.hasProperty("ametys:keywords"))
   {
       var property = node.getProperty("ametys:keywords");
       if (!property.getDefinition().isMultiple())
       {
           var value = property.getValue().getString();
           property.remove();
           
           var values = value.split(",");
           var keywords = java.lang.reflect.Array.newInstance(java.lang.String, values.length);
           for (var i=0; i < values.length; i++)
           {
               keywords[i] = values[i].trim();
           }
           ConsoleHelper.setProperty(node, "ametys:keywords", keywords);
           node.save();
           count++;
       }         
   }
}
 
println(count + " subprograms' keywords have been modified");

Établissements cohabilités devient un champ énumérés

Le champ "Etablissements cohabilités" (métadonnée "joinOrgUnit") n'est plus un texte libre mais un champ énuméré avec la liste des établissements habilités par le ministère.

Télécharger le fichiers XML de la liste des établissements : join_orgunit.xml et copiez-le dans le répertoire WEB-INF/param/odf de votre application.

Récupérer les clés i18n associées et ajoutez-les à votre catalogue application (WEB-INF/i18n/application.xml et WEB-INF/i18n/application_en.xml).

Si vous souhaitez conserver ce champ comme un texte libre vous devrez redéfinir la métadonnée "jointOrgUnit" dans le fichier WEB-INF/param/content-types/_override/org.ametys.plugins.odf.Content.program.xml


<cms:metadata name="jointOrgUnit" type="string" multiple="true">
	<label i18n="true">PLUGINS_ODF_PROGRAM_JOINT_ORGUNIT</label>
    <description i18n="true">PLUGINS_ODF_PROGRAM_JOINT_ORGUNIT_DESC</description>
</cms:metadata>        

Composante

le code RNE devient code UAI

Pour être conforme au schema CDM-fr v2, le code RNE est renommé en code UAI.

Exécutez le script suivants pour mettre à jour vos composantes existante:

var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:defaultContent)[@ametys-internal:contentType = 'org.ametys.plugins.odf.Content.orgunit']", javax.jcr.query.Query.XPATH);

var nodes = query.execute().getNodes();
  
var count = 0;
while (nodes.hasNext())
{
   var ou = nodes.next();
  
   var needSave = false;
   if (ou.hasProperty("ametys:rneCode"))
   {
       var code = ou.getProperty("ametys:rneCode").getValue().getString();
       ou.setProperty("ametys:codeUAI", code);
       needSave = true;
   }
  
   if (ou.hasProperty("ametys:rneCode_remote"))
   {
       var code = ou.getProperty("ametys:rneCode_remote").getValue().getString();
       ou.setProperty("ametys:codeUAI_remote", code);
       needSave = true;
   }
  
   if (ou.hasProperty("ametys:rneCode_sync"))
   {
       var sync = ou.getProperty("ametys:rneCode_sync").getValue().getString();
       ou.setProperty("ametys:codeUAI_sync", sync);
       needSave = true;
   }
  
   if (needSave)
   {
       count++;
       ou.save()
   }
}

println(count + " orgunits has been modified");

Changement du nom de la composante racine

Le nom du noeud JCR correpondant à la composant racine à été modifié en 3.5. Exécutez le script suivant dans la console du repository pour mettre à jour le nom du noeud :

function getOU(qm, name) {
  var xpath = "//element(*, ametys:orgunitContent)[fn:name() = '" + name + "']",
      nodeIt = qm.createQuery(xpath, javax.jcr.query.Query.XPATH).execute().getNodes();
  return nodeIt.hasNext() ? nodeIt.next() : null;
}
var oldRootOUName = 'root-orgunit',
    newRootOUName = 'orgunit-root-orgunit',
    qm = session.getWorkspace().getQueryManager(),
    oldRootOU = getOU(qm, oldRootOUName),
    newRootOU = getOU(qm, newRootOUName);
if (oldRootOU !== null)
{ 
  // delete new root OU if existing
  var path;
  if (newRootOU !== null)
  {
    var wfNode = newRootOU.getProperty('ametys-internal:workflowRef').getNode();
    path = wfNode.getPath();
    wfNode.remove();
    println("workflow node at path '" + path + "' has been removed.");
    
    path = newRootOU.getPath();
    newRootOU.remove();
    println("orgunit at path '" + path + "' has been removed.");
  }
  
  // rename old root orgunit
  path = oldRootOU.getPath();
  session.move(path, oldRootOU.getParent().getParent().getParent().getPath() + '/55/83/' + newRootOUName);
  println("orgunit at path '" + path + "' has been moved to to '" + oldRootOU.getPath() + "'.");
               
  session.save()
}
else
{
  println("No orgunit with the name '" + oldRootOUName + "' were found, nothing to do.");
}

NB: Si jamais le nom du noeud de votre ancien orgunit racine n'est pas 'root-orgunit' vous pouvez changer la valeur de la variable oldRootOUName dans le script.

Service "Liste de formations"

En 1.1.x, 1.2.x et 1.3.x, 5 services permettaient de créer un arbre des formations par domaines, diplômes, composantes ou secteurs d'activité :

  • Formations par type-domaine
  • Formations par domaines
  • Formations par type
  • Formations par composantes
  • Formation par activité

Ces 5 services ont été remplacés par un seul et uniquement service paramétrable nommé "Liste de formations", permettant de configurer le 1er et le 2e niveau de regroupement.

Migration des données

Pour migrer les instances des anciens services, exécutez le script suivant dans la console (interface repository):

var getAndRemoveBoolean = function(node, name)
{
    var value = false;
    if (node.hasProperty(name))
    {
        var prop = node.getProperty(name);
        value = prop.getBoolean();
        prop.remove();
    }
    return value;
}
 
var migrated = 0;
var xpath = "//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and ("
    + "@ametys-internal:service='org.ametys.odf.service.ProgramsByType'"
    + " or @ametys-internal:service='org.ametys.odf.service.ProgramsByDegreeDomain'"
    + " or @ametys-internal:service='org.ametys.odf.service.ProgramsByDomain'"
    + " or @ametys-internal:service='org.ametys.odf.service.ProgramsByOrgUnit'"
    + " or @ametys-internal:service='org.ametys.odf.service.ProgramsBySector')]";
 
var query = session.getWorkspace().getQueryManager().createQuery(xpath, javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
 
while (nodes.hasNext())
{
    var node = nodes.next();
    var paramsNode = node.getNode('ametys:service_parameters');
     
    var currentServiceId = node.getProperty('ametys-internal:service').getString();
    var currentServiceXSLT = paramsNode.getProperty('ametys:xslt').getString();
     
    node.setProperty('ametys-internal:service', 'org.ametys.odf.service.ProgramList');
    paramsNode.setProperty('ametys:xslt', 'pages/services/program-list/program-list_1.3.xsl');
     
    var firstLevel = '';
    var secondLevel = '';
    var alphaOrderOnFirstLevel = false;
    var alphaOrderOnSecondLevel = false;
     
    if (currentServiceId == 'org.ametys.odf.service.ProgramsByType')
    {
        firstLevel = 'degree';
        secondLevel = 'orgunit';
        alphaOrderOnFirstLevel = getAndRemoveBoolean(paramsNode, 'ametys:alphaOrderOnDegrees');
    }
    else if (currentServiceId == 'org.ametys.odf.service.ProgramsByDegreeDomain')
    {
        firstLevel = 'degree';
        secondLevel = 'domain';
        alphaOrderOnFirstLevel = getAndRemoveBoolean(paramsNode, 'ametys:alphaOrderOnDegrees');
        alphaOrderOnSecondLevel = getAndRemoveBoolean(paramsNode, 'ametys:alphaOrderOnDomains');
    }
    else if (currentServiceId == 'org.ametys.odf.service.ProgramsByDomain')
    {
        firstLevel = 'domain';
        secondLevel = 'degree';
        alphaOrderOnFirstLevel = getAndRemoveBoolean(paramsNode, 'ametys:alphaOrderOnDomains');
        alphaOrderOnSecondLevel = getAndRemoveBoolean(paramsNode, 'ametys:alphaOrderOnDegrees');
    }
    else if (currentServiceId == 'org.ametys.odf.service.ProgramsByOrgUnit')
    {
        firstLevel = 'orgunit';
        secondLevel = 'degree';
        alphaOrderOnSecondLevel = getAndRemoveBoolean(paramsNode, 'ametys:alphaOrderOnDegrees');
    }
    else if (currentServiceId == 'org.ametys.odf.service.ProgramsBySector')
    {
        firstLevel = 'sectors_activity';
        secondLevel = 'degree';
        alphaOrderOnFirstLevel = getAndRemoveBoolean(paramsNode, 'ametys:alphaOrderOnSectors');
        alphaOrderOnSecondLevel = getAndRemoveBoolean(paramsNode, 'ametys:alphaOrderOnDegrees');
    }
     
    paramsNode.setProperty('ametys:firstLevel', firstLevel);
    paramsNode.setProperty('ametys:secondLevel', secondLevel);
    paramsNode.setProperty('ametys:alphaOrderOnFirstLevel', alphaOrderOnFirstLevel);
    paramsNode.setProperty('ametys:alphaOrderOnSecondLevel', alphaOrderOnSecondLevel);
     
    migrated++;
}
 
session.save();
println('=> ' + migrated + '  programs list service(s) have been migrated.');

Migration de la charte graphique

Dans le dossier de la charte graphique, tous les répertoires "programs-by-xxx", situés dans le répertoire services/odf-web/pages/services permettant de surcharger le rendu des services, peuvent être supprimés.

Ils ont été remplacés par un seul répertoire "program-list". Toutes les éventuelles "surcharges" effectuées dans les anciennes XSL ("by-degree_1.2.xsl", "by-domain_1.2.xsl", ..) doivent être répercutés dans la nouvelle XSL "program-list/program-list_1.3.xsl"

Ancienne organisationNouvelle organisation


Service de recherche

Le service de "Recherche des formations" et "Critères de recherche" ont été fusionnés dans un seul et même service.

Migration des données

var xsltMap = {
 'pages/services/search-criteria/search-criteria.xsl': 'pages/services/search/search.xsl',
 'pages/services/search-criteria/search-criteria_1.2.xsl': 'pages/services/search/search_1.2.xsl',
 'pages/services/search-criteria/search-criteria-links_1.3.xsl': 'pages/services/search/search-links_1.3.xsl'
}
 
var qm = session.getWorkspace().getQueryManager();
var migrated = 0;
 
// Criteria for ODF search: change into ODF search, criteria-only mode.
var query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.odf.service.CriteriaForSearchService']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
 
while (nodes.hasNext())
{
 var node = nodes.next();
 var paramsNode = node.getNode('ametys:service_parameters');
 
 var message = 'Migrated ODF criteria service: ' + node.getPath();
 
 var currentServiceXSLT = paramsNode.getProperty('ametys:xslt').getString();
 
 node.setProperty('ametys-internal:service', 'org.ametys.odf.service.SearchService');
 paramsNode.setProperty('ametys:search-mode', 'criteria-only');
 
 if (xsltMap[currentServiceXSLT] != null)
 {
 paramsNode.setProperty('ametys:xslt', xsltMap[currentServiceXSLT]);
 message += ', new xslt is: ' + xsltMap[currentServiceXSLT];
 }
 
 println(message);
 
 migrated++;
}
 
// ODF search: change the search mode.
query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.odf.service.SearchService']/ametys:service_parameters[@ametys:on-same-page]", javax.jcr.query.Query.XPATH);
nodes = query.execute().getNodes();
 
while (nodes.hasNext())
{
 var node = nodes.next();
 
 var onSamePage = node.getProperty('ametys:on-same-page').getBoolean();
 var mode = onSamePage ? 'criteria-and-results' : 'criteria-or-results';
 
 node.setProperty('ametys:search-mode', mode);
 
 println('Migrated ODF search service parameters.');
 
 migrated++;
}
 
println('=> ' + migrated + ' ODF search service(s) have been migrated.');
 
session.save();

Migration de la charte graphique

Dans la charte graphique, le répertoire "search-criteria", situé dans le répertoire services/odf-web/pages/services doit être déplacé dans le répertoire services/odf-web/pages/services/search.

Service "insérer un contenu"

Si vous utilisiez le service "insérer un contenu" avec des formations, exécutez le script suivant :

var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.web.service.InsertContentService']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
  
var count = 0;
while (nodes.hasNext())
{
  var zone = nodes.next();
  var serviceParameter = zone.getNode("ametys:service_parameters");
  
  if (serviceParameter.hasProperty("ametys:contentId"))
  {
      var contentId = serviceParameter.getProperty("ametys:contentId").getValue().getString();

      if (contentId.indexOf("programContent") != -1)
      {
        zone.setProperty("ametys-internal:service", "org.ametys.odf.service.InsertProgram");
        zone.save();
        count++;
      }
  }
}

println(count + " service(s) of ODF insert content have been migrated");

 

 

Fichiers SQLMap pour Apogée

Les objets sqlMap définis dans les fichiers de mapping (WEB-INF/param/odf/apogee) ont changé de package.

Voici ci-dessus la nouvelle correspondance id - class.

FichierIdClass
programs.xml



searchProgramItemorg.ametys.plugins.odfsync.apogee.searchitem.ApogeeProgramSearchRemoteItem
programorg.ametys.plugins.odfsync.apogee.item.ApogeeProgramRemoteItem
steporg.ametys.plugins.odfsync.apogee.item.ApogeeSubProgramRemoteItem
stepItemorg.ametys.plugins.odfsync.apogee.searchitem.ApogeeSubProgramSearchRemoteItem
stepElementorg.ametys.plugins.odfsync.apogee.item.ApogeeELPRemoteItem
orgUnits.xml

orgUnit, associatedOrgUnit, rootOrgUnitorg.ametys.plugins.odfsync.apogee.item.ApogeeOrgUnitRemoteItem
orgUnitSearchItemorg.ametys.plugins.odfsync.apogee.searchitem.ApogeeOrgUnitSearchRemoteItem
educationalElements.xmleducationalElementorg.ametys.plugins.odfsync.apogee.item.ApogeeCourseRemoteItem
educationalElementSearchItemorg.ametys.plugins.odfsync.apogee.searchitem.ApogeeCourseSearchRemoteItem
educationalElementContainerorg.ametys.plugins.odfsync.apogee.item.ApogeeContainerRemoteItem
educationalElementSearchContainerorg.ametys.plugins.odfsync.apogee.searchitem.ApogeeContainerSearchRemoteItem
courseListSearchItemorg.ametys.plugins.odfsync.apogee.item.ApogeeCourseListRemoteItem
courseListorg.ametys.plugins.odfsync.apogee.item.ApogeeCourseListRemoteItem

Fichiers de conversion Apogée

Les fichiers permettant de faire la conversion des codes Apogée ont été déplacés.

Les fichiers de la liste ci-dessous, initialement situés dans le répertoire WEB-INF/param/apogee, doivent être déplacés dans le répertoire WEB-INF/param/apogee/codede votre application:

Ils doivent être placés dans le répertoire WEB-INF/param/apogee/code de votre application:

Fichier runtime.xml

Si vous utilisez la synchronisation Apogée, le fichier WEB-INF/params/runtime.xml doit contenir les lignes suivantes:

<org.ametys.plugins.odfsync.ODFSyncManager>org.ametys.plugins.odfsync.apogee.ApogeeODFSyncManager</org.ametys.plugins.odfsync.ODFSyncManager>
<org.ametys.plugins.odfsync.apogee.ApogeeSynchronizationHelper>org.ametys.plugins.odfsync.apogee.DefaultApogeeSynchronizationHelper</org.ametys.plugins.odfsync.apogee.ApogeeSynchronizationHelper>
<org.ametys.plugins.odfsync.apogee.ApogeeDAO>org.ametys.plugins.odfsync.apogee.DefaultApogeeDAO</org.ametys.plugins.odfsync.apogee.ApogeeDAO>

Dans la section <exclude> ... </exclude>, vérifiez que les features odf-sync/synchronization.apogee.datasource  et odf-sync/odf.rights.sync.others ne sont pas désactivées. Si c'est le cas, supprimez-les de cette section.

Rendez-vous sur le manuel d'intégration pour connaitre la paramétrage complet d'une application ODF 2.x : Manuel intégrateur

 

Fichier de ribbon

Dans le fichier cms-ribbon-default.xml vous devez importer le ribbon propre à l'offre de formation :

  • si vous utilisez la synchronisation Apogée

    <import>plugin:odf-sync://cms-ribbon-web-apogee.xml</import>
    
  • si vous n'utilisez pas la synchronisation Apogée

    <import>plugin:odf-web://cms-ribbon.xml</import>
    

Rendez-vous sur le manuel d'intégration pour connaitre la paramétrage complet d'une application ODF 2.x : Manuel intégrateur

 

Workflow

Le plugin odf-workflow n'existe plus. Chaque application doit avoir son propre plugin définissant les actions de workflow disponibles. Vous pouvez trouver un exemple de plugin ici http://viewvc.ametys.org/viewvc/ametys/trunk/templates/odfweb/trunk/webapp/cms/plugins/default-odf-workflow/

 

Plugin ODF

Plugin ODF-Web

Plugin ODF-Sync

x  

xx 

x x

xx x
Retour en haut