Reportez-vous au tableau de compatibilité des plugins et incrémentez les versions de vos plugins (prendre pour chaque plugin la version la plus récente compatible 4.2)
Fichiers de paramètrage (WEB-INF/params)
runtime.xml
Dans le runtime.xml, supprimez les lignes les lignes suivantes:
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
Dans vos modèles de recherche (les fichiers XML sous WEB-INF/param/search), remplacer les occurrences de IndexingStringFieldAggregatorSearchUICriterion par IndexingFieldAggregatorSearchUICriterion
Fichiers de configuration ($AMETYS_HOME/config)
Connexion par email
Les options de configuration du mode d'authentification par formulaire (FormsCredentialProvider) ont été modifiées:
le niveau de sécurité a été "splité" en 2 options : autoriser cookie et protection par captcha
un nouveau paramètre permet d'autoriser la connexion en utilisant l'email comme identifiant
Le fichier $AMETYS_HOME/config/user-population.xml doit être modifié manuellement. Remplacez :
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
Le paramètre "tri des résultats" a été remonté des populations de type "Annuaire LDAP" directement dans la source de données, notamment pour être aussi utilisé par les répertoires de groupes. Dans vos fichiers $AMETYS_HOME/config/user-populations.xml, supprimez toutes les occurrences du paramètre suivant, si présent :
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
Et dans vos fichiers $AMETYS_HOME/config/datasources-ldap.xml, ajoutez à chaque source de données le paramètre suivant :
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
<serverSideSorting>true</serverSideSorting>
<serverSideSorting>true</serverSideSorting>
<serverSideSorting>true</serverSideSorting>
La valeur par défaut est "true". Cependant, si vous aviez décochés "Tri des résultats", c-à-d que vous aviez un "runtime.users.ldap.serverSideSorting" à false dans vos ou votre population(s) annuaire LDAP pour des raisons de performances, alors mettez la valeur à "false" au lieu de "true" dans le $AMETYS_HOME/config/datasources-ldap.xml aux sources de données correspondantes
Fichiers de workflows
Le fichier WEB-INF/param/workflows.xml est devenu facultatif. Les workflows disponible sont automatiquement lus à partir du contenu du dossier WEB-INF/param/workflows.
Créez un nouveau dossier WEB-INF/param/workflows.
Ouvrez le fichier WEB-INF/param/workflows.xml.
Pour chaque ligne, déplacez le fichier indiqué dans l'attribut "location" vers le nouveau dossier
Renommez ce fichier avec le contenu de l'attribut "name" auquel vous ajoutez l'extension ".xml"
Supprimez le fichier WEB-INF/param/workflows.xml.
En général, il suffit d'enlever le préfixe "workflow-" devant le nom du fichier, mais attention il y a quelques pièges... par exemple "worfklow.xml" qui devient "content.xml" ; ou "workflow-coursepart.xml" qui devient "course-part.xml". Soyez attentif à l'attribut "name" du fichier workflows.xml
Workflow des tables de référence
Dans le fichier workflows/reference-table.xml pour les tables de référence, rajoutez l'action suivante dans les <common-actions> :
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
Sur tous les workflows utilisés en synchronisation (c'est à dire utilisant l'action 800), ajoutez à l'action de synchronisation 800 la post-fonction org.ametys.cms.workflow.ExtractOutgoingReferencesFunction :
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
Pour simplifier l'installation de certains plugins, il y a maintenant un point d'extension pour les fonctions 'après enregistrement' et 'après validation'.
Les endroits où vous aviez la fonction de workflow du plugin forms ou du plugin translation-flagging seront remplacés par des fonctions génériques.
Par exemple, la fonction : org.ametys.plugins.forms.workflow.FormEditionFunction devient
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
Les tokens pouvaient être à usage infini ou à usage unique. Maintenant ils peuvent avoir un nombre limité d'utilisation, avoir leur durée renouvelable et avoir un contexte d'utilisation.
Des scripts de migration SQL sont à exécuter afin de pouvoir mettre à jour le format des tables (en fonction de votre type de base de données.
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
#Derby
ALTER TABLE APP.Authentication_Token ADD nb_uses_left int;
ALTER TABLE APP.Authentication_Token ADD auto_renew_duration bigint;
ALTER TABLE APP.Authentication_Token ADD context VARCHAR(200);
UPDATE APP.Authentication_Token SET nb_uses_left = 1 WHERE end_date IS NOT NULL;
RENAME COLUMN APP.Authentication_Token.comment TO token_comment;
#HsqlDb
ALTER TABLE Authentication_Token ADD nb_uses_left INTEGER NULL BEFORE context;
ALTER TABLE Authentication_Token ADD auto_renew_duration NUMERIC(13) NULL BEFORE context;
ALTER TABLE Authentication_Token ADD context VARCHAR(200) NULL BEFORE context;
UPDATE Authentication_Token SET nb_uses_left = 1 WHERE end_date IS NOT NULL;
ALTER TABLE Authentication_Token ALTER COLUMN comment RENAME TO token_comment;
#MySQL
ALTER TABLE Authentication_Token
ADD nb_uses_left INT NULL AFTER last_update_date,
ADD auto_renew_duration BIGINT NULL AFTER nb_uses_left,
ADD context VARCHAR(200) NULL AFTER auto_renew_duration;
UPDATE Authentication_Token SET nb_uses_left = 1 WHERE end_date IS NOT NULL;
ALTER TABLE Authentication_Token CHANGE comment token_comment LONGBLOB;
#Oracle
ALTER TABLE Authentication_Token ADD
(
nb_uses_left NUMBER,
auto_renew_duration NUMBER(13),
context VARCHAR(200)
);
UPDATE Authentication_Token SET nb_uses_left = 1 WHERE end_date IS NOT NULL;
ALTER TABLE Authentication_Token RENAME COLUMN comment TO token_comment;
#PostgreSql
ALTER TABLE Authentication_Token
ADD nb_uses_left INTEGER NULL,
ADD auto_renew_duration BIGINT NULL,
ADD context VARCHAR(200) NULL;
UPDATE Authentication_Token SET nb_uses_left = 1 WHERE end_date IS NOT NULL;
ALTER TABLE Authentication_Token RENAME COLUMN comment TO token_comment;
#Derby
ALTER TABLE APP.Authentication_Token ADD nb_uses_left int;
ALTER TABLE APP.Authentication_Token ADD auto_renew_duration bigint;
ALTER TABLE APP.Authentication_Token ADD context VARCHAR(200);
UPDATE APP.Authentication_Token SET nb_uses_left = 1 WHERE end_date IS NOT NULL;
RENAME COLUMN APP.Authentication_Token.comment TO token_comment;
#HsqlDb
ALTER TABLE Authentication_Token ADD nb_uses_left INTEGER NULL BEFORE context;
ALTER TABLE Authentication_Token ADD auto_renew_duration NUMERIC(13) NULL BEFORE context;
ALTER TABLE Authentication_Token ADD context VARCHAR(200) NULL BEFORE context;
UPDATE Authentication_Token SET nb_uses_left = 1 WHERE end_date IS NOT NULL;
ALTER TABLE Authentication_Token ALTER COLUMN comment RENAME TO token_comment;
#MySQL
ALTER TABLE Authentication_Token
ADD nb_uses_left INT NULL AFTER last_update_date,
ADD auto_renew_duration BIGINT NULL AFTER nb_uses_left,
ADD context VARCHAR(200) NULL AFTER auto_renew_duration;
UPDATE Authentication_Token SET nb_uses_left = 1 WHERE end_date IS NOT NULL;
ALTER TABLE Authentication_Token CHANGE comment token_comment LONGBLOB;
#Oracle
ALTER TABLE Authentication_Token ADD
(
nb_uses_left NUMBER,
auto_renew_duration NUMBER(13),
context VARCHAR(200)
);
UPDATE Authentication_Token SET nb_uses_left = 1 WHERE end_date IS NOT NULL;
ALTER TABLE Authentication_Token RENAME COLUMN comment TO token_comment;
#PostgreSql
ALTER TABLE Authentication_Token
ADD nb_uses_left INTEGER NULL,
ADD auto_renew_duration BIGINT NULL,
ADD context VARCHAR(200) NULL;
UPDATE Authentication_Token SET nb_uses_left = 1 WHERE end_date IS NOT NULL;
ALTER TABLE Authentication_Token RENAME COLUMN comment TO token_comment;
#Derby
ALTER TABLE APP.Authentication_Token ADD nb_uses_left int;
ALTER TABLE APP.Authentication_Token ADD auto_renew_duration bigint;
ALTER TABLE APP.Authentication_Token ADD context VARCHAR(200);
UPDATE APP.Authentication_Token SET nb_uses_left = 1 WHERE end_date IS NOT NULL;
RENAME COLUMN APP.Authentication_Token.comment TO token_comment;
#HsqlDb
ALTER TABLE Authentication_Token ADD nb_uses_left INTEGER NULL BEFORE context;
ALTER TABLE Authentication_Token ADD auto_renew_duration NUMERIC(13) NULL BEFORE context;
ALTER TABLE Authentication_Token ADD context VARCHAR(200) NULL BEFORE context;
UPDATE Authentication_Token SET nb_uses_left = 1 WHERE end_date IS NOT NULL;
ALTER TABLE Authentication_Token ALTER COLUMN comment RENAME TO token_comment;
#MySQL
ALTER TABLE Authentication_Token
ADD nb_uses_left INT NULL AFTER last_update_date,
ADD auto_renew_duration BIGINT NULL AFTER nb_uses_left,
ADD context VARCHAR(200) NULL AFTER auto_renew_duration;
UPDATE Authentication_Token SET nb_uses_left = 1 WHERE end_date IS NOT NULL;
ALTER TABLE Authentication_Token CHANGE comment token_comment LONGBLOB;
#Oracle
ALTER TABLE Authentication_Token ADD
(
nb_uses_left NUMBER,
auto_renew_duration NUMBER(13),
context VARCHAR(200)
);
UPDATE Authentication_Token SET nb_uses_left = 1 WHERE end_date IS NOT NULL;
ALTER TABLE Authentication_Token RENAME COLUMN comment TO token_comment;
#PostgreSql
ALTER TABLE Authentication_Token
ADD nb_uses_left INTEGER NULL,
ADD auto_renew_duration BIGINT NULL,
ADD context VARCHAR(200) NULL;
UPDATE Authentication_Token SET nb_uses_left = 1 WHERE end_date IS NOT NULL;
ALTER TABLE Authentication_Token RENAME COLUMN comment TO token_comment;
Inscription des utilisateurs FO
Lors de la demande de création de compte, on ne demande plus les nom et prénoms (qui seront demandées plus tard).
Exécutez les scripts suivants sur votre base de données :
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
alter table Users_Temp drop lastname;
alter table Users_Temp drop firstname;
alter table Users_Temp drop lastname;
alter table Users_Temp drop firstname;
alter table Users_Temp drop lastname;
alter table Users_Temp drop firstname;
Modification d'API
Boutons du ribbon
Dans vos fichiers java et plugin.xml, recherchez et remplacez les occurrences de la 1ere colonne du tableau par leur équivalent dans la 2e colonne:
La gestion des paramètres de service a été complètement modifiée. Lors de la migration d'un projet en 4.2, si ce projet contient des services spécifiques ou surcharge des services du noyau (sauf s'il ne surcharge que le rendu), cette migration risque de nécessiter des modifications de code.
Paramétrage des PDF (fonts personnalisées)
Dans certains projets (principalement ODF) les pipelines faisant appel à des PDF ont été modifiés pour intégrer des fonts personnalisées. Les pipelines personnalisés dans ce but ne sont donc plus utiles, il faut supprimer leurs appels et leurs déclarations. Vous pouvez les détecter en cherchant les serializers (sitemap.xmap) org.ametys.core.cocoon.FOPNGSerializer ayant une balise <user-config>. Les pipelines noyaux font désormais correctement l'appel à la configuration personnalisée.
Vérifier qu'il n'existe pas d'autres serializers spécifique au projet en cherchant <map:serialize type="fo2pdf"/>.
Cependant, il est possible que vous deviez modifier votre projet si le fichier n'est pas bien positionné. Se référer à la page Mettre une font personnalisée dans un PDF pour de plus amples informations.
Paramètres de configuration
Url du back-office
Dans les paramètres de configuration générale, l'url du CMS ne peut plus se terminer par / ou par /index.html. Vous devez modifiez ce paramètre si c'est le cas.
Migration des données
Serveur éteint, commencez par supprimer le fichier $AMETYS_HOME/data/repository/repository/custom_nodetypes.xml puis redémarrer.
Dans la console d'administration exécutez les scripts suivants :
Migration des étiquettes
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
function copyTagNode(originalNode, newNode)
{
setPropertyFromNode(originalNode, newNode, "ametys-internal:target");
setPropertyFromNode(originalNode, newNode, "ametys-internal:description");
setPropertyFromNode(originalNode, newNode, "ametys-internal:visibility");
setPropertyFromNode(originalNode, newNode, "ametys-internal:title");
}
function setPropertyFromNode(originalNode, newNode, propertyName)
{
if (originalNode.hasProperty(propertyName))
{
newNode.setProperty(propertyName, originalNode.getProperty(propertyName).getString());
}
}
function createNodesFromNode(rootNode, sourceNode)
{
var nbTag = 0;
var childNodes = sourceNode.getNodes();
while (childNodes.hasNext())
{
var childNode = childNodes.next();
var createdNode = rootNode.addNode(childNode.getName(), "ametys:cmstag");
copyTagNode(childNode, createdNode);
nbTag++;
nbTag += createNodesFromNode(createdNode, childNode);
}
return nbTag;
}
var totalNbTag = 0;
var qm = session.getWorkspace().getQueryManager();
var query = qm.createQuery("//element(*, ametys:tags)", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var tagsNode = nodes.next();
if (!tagsNode.getParent().hasNode("cmstags"))
{
tagsNode.getParent().addNode("cmstags", "ametys:cmstags");
}
var newTagsNode = tagsNode.getParent().getNode("cmstags");
totalNbTag += createNodesFromNode(newTagsNode, tagsNode);
tagsNode.remove();
}
session.save();
print(totalNbTag + " tag(s) have been migrated");
function copyTagNode(originalNode, newNode)
{
setPropertyFromNode(originalNode, newNode, "ametys-internal:target");
setPropertyFromNode(originalNode, newNode, "ametys-internal:description");
setPropertyFromNode(originalNode, newNode, "ametys-internal:visibility");
setPropertyFromNode(originalNode, newNode, "ametys-internal:title");
}
function setPropertyFromNode(originalNode, newNode, propertyName)
{
if (originalNode.hasProperty(propertyName))
{
newNode.setProperty(propertyName, originalNode.getProperty(propertyName).getString());
}
}
function createNodesFromNode(rootNode, sourceNode)
{
var nbTag = 0;
var childNodes = sourceNode.getNodes();
while (childNodes.hasNext())
{
var childNode = childNodes.next();
var createdNode = rootNode.addNode(childNode.getName(), "ametys:cmstag");
copyTagNode(childNode, createdNode);
nbTag++;
nbTag += createNodesFromNode(createdNode, childNode);
}
return nbTag;
}
var totalNbTag = 0;
var qm = session.getWorkspace().getQueryManager();
var query = qm.createQuery("//element(*, ametys:tags)", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var tagsNode = nodes.next();
if (!tagsNode.getParent().hasNode("cmstags"))
{
tagsNode.getParent().addNode("cmstags", "ametys:cmstags");
}
var newTagsNode = tagsNode.getParent().getNode("cmstags");
totalNbTag += createNodesFromNode(newTagsNode, tagsNode);
tagsNode.remove();
}
session.save();
print(totalNbTag + " tag(s) have been migrated");
function copyTagNode(originalNode, newNode)
{
setPropertyFromNode(originalNode, newNode, "ametys-internal:target");
setPropertyFromNode(originalNode, newNode, "ametys-internal:description");
setPropertyFromNode(originalNode, newNode, "ametys-internal:visibility");
setPropertyFromNode(originalNode, newNode, "ametys-internal:title");
}
function setPropertyFromNode(originalNode, newNode, propertyName)
{
if (originalNode.hasProperty(propertyName))
{
newNode.setProperty(propertyName, originalNode.getProperty(propertyName).getString());
}
}
function createNodesFromNode(rootNode, sourceNode)
{
var nbTag = 0;
var childNodes = sourceNode.getNodes();
while (childNodes.hasNext())
{
var childNode = childNodes.next();
var createdNode = rootNode.addNode(childNode.getName(), "ametys:cmstag");
copyTagNode(childNode, createdNode);
nbTag++;
nbTag += createNodesFromNode(createdNode, childNode);
}
return nbTag;
}
var totalNbTag = 0;
var qm = session.getWorkspace().getQueryManager();
var query = qm.createQuery("//element(*, ametys:tags)", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var tagsNode = nodes.next();
if (!tagsNode.getParent().hasNode("cmstags"))
{
tagsNode.getParent().addNode("cmstags", "ametys:cmstags");
}
var newTagsNode = tagsNode.getParent().getNode("cmstags");
totalNbTag += createNodesFromNode(newTagsNode, tagsNode);
tagsNode.remove();
}
session.save();
print(totalNbTag + " tag(s) have been migrated");
Service inscription des utilisateurs
Les paramètres du service ont été modifiés :
Le choix du mode d'affichage des CGU devient une liste déroulante : jamais / lien vers une page / insertion d'un contenu
Le choix du comportement à la fin de la création du compte : message standard / message standard et lien vers une page / insertion d'un contenu
Exécutez le script JCR suivant pour modifier les services existants:
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
var count = 0;
var qm = session.getWorkspace().getQueryManager();
var query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:service = 'org.ametys.web.service.UserSignup']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
var page = node.getParent().getParent().getParent().getParent();
var sitemap = page.getProperty("ametys:sitemap").getString();
print("Found a signup service for language " + sitemap + " at path " + page.getPath());
count++;
var params = node.getNode("ametys:service_parameters");
if (params.hasProperty("ametys:terms-of-service-page"))
{
var pageId = params.getProperty("ametys:terms-of-service-page").getString();
if (pageId != '')
{
params.setProperty("ametys:terms-of-service-mode", "PAGE");
}
else
{
params.setProperty("ametys:terms-of-service-mode", "NONE");
}
}
else
{
params.setProperty("ametys:terms-of-service-mode", "NONE");
}
query = qm.createQuery("//element(*, ametys:page)[@ametys-internal:tags = 'USER_PREFS_MAIN' and @ametys:sitemap= " + sitemap + "]", javax.jcr.query.Query.XPATH);
var pages = query.execute().getNodes();
if (pages.hasNext())
{
var successPage = pages.next();
params.setProperty("ametys:success-page", "page://" + successPage.getUUID());
params.setProperty("ametys:success-mode", "PAGE");
}
// TO UNCOMMENT ONLY IF YOU USE USER-DIRECTORY PLUGIN
// params.setProperty("ametys:xslt", pages/services/user-signup/signup.xsl);
}
session.save();
print(count + " signup services have been migrated");
var count = 0;
var qm = session.getWorkspace().getQueryManager();
var query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:service = 'org.ametys.web.service.UserSignup']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
var page = node.getParent().getParent().getParent().getParent();
var sitemap = page.getProperty("ametys:sitemap").getString();
print("Found a signup service for language " + sitemap + " at path " + page.getPath());
count++;
var params = node.getNode("ametys:service_parameters");
if (params.hasProperty("ametys:terms-of-service-page"))
{
var pageId = params.getProperty("ametys:terms-of-service-page").getString();
if (pageId != '')
{
params.setProperty("ametys:terms-of-service-mode", "PAGE");
}
else
{
params.setProperty("ametys:terms-of-service-mode", "NONE");
}
}
else
{
params.setProperty("ametys:terms-of-service-mode", "NONE");
}
query = qm.createQuery("//element(*, ametys:page)[@ametys-internal:tags = 'USER_PREFS_MAIN' and @ametys:sitemap= " + sitemap + "]", javax.jcr.query.Query.XPATH);
var pages = query.execute().getNodes();
if (pages.hasNext())
{
var successPage = pages.next();
params.setProperty("ametys:success-page", "page://" + successPage.getUUID());
params.setProperty("ametys:success-mode", "PAGE");
}
// TO UNCOMMENT ONLY IF YOU USE USER-DIRECTORY PLUGIN
// params.setProperty("ametys:xslt", pages/services/user-signup/signup.xsl);
}
session.save();
print(count + " signup services have been migrated");
var count = 0;
var qm = session.getWorkspace().getQueryManager();
var query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:service = 'org.ametys.web.service.UserSignup']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
var page = node.getParent().getParent().getParent().getParent();
var sitemap = page.getProperty("ametys:sitemap").getString();
print("Found a signup service for language " + sitemap + " at path " + page.getPath());
count++;
var params = node.getNode("ametys:service_parameters");
if (params.hasProperty("ametys:terms-of-service-page"))
{
var pageId = params.getProperty("ametys:terms-of-service-page").getString();
if (pageId != '')
{
params.setProperty("ametys:terms-of-service-mode", "PAGE");
}
else
{
params.setProperty("ametys:terms-of-service-mode", "NONE");
}
}
else
{
params.setProperty("ametys:terms-of-service-mode", "NONE");
}
query = qm.createQuery("//element(*, ametys:page)[@ametys-internal:tags = 'USER_PREFS_MAIN' and @ametys:sitemap= " + sitemap + "]", javax.jcr.query.Query.XPATH);
var pages = query.execute().getNodes();
if (pages.hasNext())
{
var successPage = pages.next();
params.setProperty("ametys:success-page", "page://" + successPage.getUUID());
params.setProperty("ametys:success-mode", "PAGE");
}
// TO UNCOMMENT ONLY IF YOU USE USER-DIRECTORY PLUGIN
// params.setProperty("ametys:xslt", pages/services/user-signup/signup.xsl);
}
session.save();
print(count + " signup services have been migrated");
Changement de format de stockage des données multilingues
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
var fieldsByContent = new java.util.HashMap();
fillFieldsToMigrateMap();
var migratedFields = 0;
var migratedContents = 0;
// Migrate the multilingual nodes content by content
fieldsByContent.forEach(
function(contentId)
{
var content = ametysResolver.resolveById("content://" + contentId);
migrateContent(content,
[renameMultilingualString],
true /* old versions have to be marked incompatible */,
null /* tag new versions */,
false /* not verbose - DO NOT ACTIVATE IN THIS CASE !! */
);
}
);
print(migratedFields + " multilingual fields have been migrated in " + migratedContents + " contents.");
// Get all the multilingual nodes
function fillFieldsToMigrateMap()
{
var fieldsToMigrate = 0;
var qm = session.getWorkspace().getQueryManager();
var query = qm.createQuery("//element(*, ametys:multilingualString)", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
// Get the path of the multilingual metadata to migrate
var metadataPath = "";
var contentNode = node;
while (!contentNode.getPrimaryNodeType().isNodeType("ametys:content"))
{
metadataPath += node.getName() + "/";
contentNode = node.getParent();
}
metadataPath = metadataPath.slice(0, -1);
// Store the metadataPath to migrate by content ID
var contentId = contentNode.getIdentifier();
var fields = fieldsByContent.getOrDefault(contentId, new java.util.HashSet());
fields.add(metadataPath);
fieldsByContent.put(contentId, fields);
fieldsToMigrate++;
}
print(fieldsToMigrate + " multilingual fields to migrate potentially in " + fieldsByContent.keySet().size() + " contents.");
}
// Migrate the multilingual strings of the content and increment the global counter
function renameMultilingualString(content)
{
var migratedContent = false;
var contentId = content.getNode().getIdentifier();
// Get all metadata to migrate for the current content
var fields = fieldsByContent.get(contentId);
fields.forEach(
function(fieldName)
{
var migratedField = false;
var fieldNode = content.getNode().getNode(fieldName);
var properties = fieldNode.getProperties();
while (properties.hasNext())
{
var property = properties.nextProperty();
// If the current property name doesn't starts with "ametys:" ...
var propertyName = property.getName();
if (propertyName.indexOf(":") == -1)
{
// ... move it to "ametys:[propertyName]"
fieldNode.setProperty("ametys:" + propertyName, property.getValue());
property.remove();
migratedField = true;
}
}
if (migratedField)
{
migratedFields++;
migratedContent = true;
}
}
);
if (migratedContent)
{
migratedContents++;
}
}
var fieldsByContent = new java.util.HashMap();
fillFieldsToMigrateMap();
var migratedFields = 0;
var migratedContents = 0;
// Migrate the multilingual nodes content by content
fieldsByContent.forEach(
function(contentId)
{
var content = ametysResolver.resolveById("content://" + contentId);
migrateContent(content,
[renameMultilingualString],
true /* old versions have to be marked incompatible */,
null /* tag new versions */,
false /* not verbose - DO NOT ACTIVATE IN THIS CASE !! */
);
}
);
print(migratedFields + " multilingual fields have been migrated in " + migratedContents + " contents.");
// Get all the multilingual nodes
function fillFieldsToMigrateMap()
{
var fieldsToMigrate = 0;
var qm = session.getWorkspace().getQueryManager();
var query = qm.createQuery("//element(*, ametys:multilingualString)", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
// Get the path of the multilingual metadata to migrate
var metadataPath = "";
var contentNode = node;
while (!contentNode.getPrimaryNodeType().isNodeType("ametys:content"))
{
metadataPath += node.getName() + "/";
contentNode = node.getParent();
}
metadataPath = metadataPath.slice(0, -1);
// Store the metadataPath to migrate by content ID
var contentId = contentNode.getIdentifier();
var fields = fieldsByContent.getOrDefault(contentId, new java.util.HashSet());
fields.add(metadataPath);
fieldsByContent.put(contentId, fields);
fieldsToMigrate++;
}
print(fieldsToMigrate + " multilingual fields to migrate potentially in " + fieldsByContent.keySet().size() + " contents.");
}
// Migrate the multilingual strings of the content and increment the global counter
function renameMultilingualString(content)
{
var migratedContent = false;
var contentId = content.getNode().getIdentifier();
// Get all metadata to migrate for the current content
var fields = fieldsByContent.get(contentId);
fields.forEach(
function(fieldName)
{
var migratedField = false;
var fieldNode = content.getNode().getNode(fieldName);
var properties = fieldNode.getProperties();
while (properties.hasNext())
{
var property = properties.nextProperty();
// If the current property name doesn't starts with "ametys:" ...
var propertyName = property.getName();
if (propertyName.indexOf(":") == -1)
{
// ... move it to "ametys:[propertyName]"
fieldNode.setProperty("ametys:" + propertyName, property.getValue());
property.remove();
migratedField = true;
}
}
if (migratedField)
{
migratedFields++;
migratedContent = true;
}
}
);
if (migratedContent)
{
migratedContents++;
}
}
var fieldsByContent = new java.util.HashMap();
fillFieldsToMigrateMap();
var migratedFields = 0;
var migratedContents = 0;
// Migrate the multilingual nodes content by content
fieldsByContent.forEach(
function(contentId)
{
var content = ametysResolver.resolveById("content://" + contentId);
migrateContent(content,
[renameMultilingualString],
true /* old versions have to be marked incompatible */,
null /* tag new versions */,
false /* not verbose - DO NOT ACTIVATE IN THIS CASE !! */
);
}
);
print(migratedFields + " multilingual fields have been migrated in " + migratedContents + " contents.");
// Get all the multilingual nodes
function fillFieldsToMigrateMap()
{
var fieldsToMigrate = 0;
var qm = session.getWorkspace().getQueryManager();
var query = qm.createQuery("//element(*, ametys:multilingualString)", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
// Get the path of the multilingual metadata to migrate
var metadataPath = "";
var contentNode = node;
while (!contentNode.getPrimaryNodeType().isNodeType("ametys:content"))
{
metadataPath += node.getName() + "/";
contentNode = node.getParent();
}
metadataPath = metadataPath.slice(0, -1);
// Store the metadataPath to migrate by content ID
var contentId = contentNode.getIdentifier();
var fields = fieldsByContent.getOrDefault(contentId, new java.util.HashSet());
fields.add(metadataPath);
fieldsByContent.put(contentId, fields);
fieldsToMigrate++;
}
print(fieldsToMigrate + " multilingual fields to migrate potentially in " + fieldsByContent.keySet().size() + " contents.");
}
// Migrate the multilingual strings of the content and increment the global counter
function renameMultilingualString(content)
{
var migratedContent = false;
var contentId = content.getNode().getIdentifier();
// Get all metadata to migrate for the current content
var fields = fieldsByContent.get(contentId);
fields.forEach(
function(fieldName)
{
var migratedField = false;
var fieldNode = content.getNode().getNode(fieldName);
var properties = fieldNode.getProperties();
while (properties.hasNext())
{
var property = properties.nextProperty();
// If the current property name doesn't starts with "ametys:" ...
var propertyName = property.getName();
if (propertyName.indexOf(":") == -1)
{
// ... move it to "ametys:[propertyName]"
fieldNode.setProperty("ametys:" + propertyName, property.getValue());
property.remove();
migratedField = true;
}
}
if (migratedField)
{
migratedFields++;
migratedContent = true;
}
}
);
if (migratedContent)
{
migratedContents++;
}
}
Ancien service de recherche
Le service de moteur de recherche principal a été renommé en "Recherche de pages".
L'url de service associée a été changée de "service/search.html" vers "service/search-pages.html". Vérifiez dans vos XSL que vous n'aviez pas cette url qui apparaissait.
La classe du service a changé. Si le moteur de recherche a été dupliqué, cherchez dans les fichiers xml de votre projet et remplacez "org.ametys.web.frontoffice.SearchService" par "org.ametys.web.frontoffice.SearchPagesService".
L'emplacement des XSL du service à changé (voir migration graphique) il faut donc exécuter le script suivant (et reconstruire le live s'il y a des modifications):
Oups !
La copie dans le presse papier a échouée. Ouvrez le code et copier-le manuellement.
var count = 0;
var done = 0;
jcrXPathQuery("//element(*, ametys:zoneItem)[@ametys-internal:service='org.ametys.web.service.FrontSearchService']").forEach(function(zi) {
print("Found " + zi.getPath());
var parameters = zi.getServiceParameters();
var xsltParam = parameters.getValue("xslt");
print(" " + xsltParam);
count++;
var toReplace = "pages/services/search/";
if (xsltParam.startsWith(toReplace))
{
var newValue = "pages/services/search-pages/" + xsltParam.substring(toReplace.length);
print(" => " + newValue)
parameters.setValue("xslt", newValue);
zi.saveChanges();
done++;
}
else
{
print(" => ok")
}
})
print("...");
print(done + " services modifiés sur " + count)
if (done > 0)
{
print("PENSEZ A RECONSTRUIRE LE LIVE")
}
var count = 0;
var done = 0;
jcrXPathQuery("//element(*, ametys:zoneItem)[@ametys-internal:service='org.ametys.web.service.FrontSearchService']").forEach(function(zi) {
print("Found " + zi.getPath());
var parameters = zi.getServiceParameters();
var xsltParam = parameters.getValue("xslt");
print(" " + xsltParam);
count++;
var toReplace = "pages/services/search/";
if (xsltParam.startsWith(toReplace))
{
var newValue = "pages/services/search-pages/" + xsltParam.substring(toReplace.length);
print(" => " + newValue)
parameters.setValue("xslt", newValue);
zi.saveChanges();
done++;
}
else
{
print(" => ok")
}
})
print("...");
print(done + " services modifiés sur " + count)
if (done > 0)
{
print("PENSEZ A RECONSTRUIRE LE LIVE")
}
var count = 0;
var done = 0;
jcrXPathQuery("//element(*, ametys:zoneItem)[@ametys-internal:service='org.ametys.web.service.FrontSearchService']").forEach(function(zi) {
print("Found " + zi.getPath());
var parameters = zi.getServiceParameters();
var xsltParam = parameters.getValue("xslt");
print(" " + xsltParam);
count++;
var toReplace = "pages/services/search/";
if (xsltParam.startsWith(toReplace))
{
var newValue = "pages/services/search-pages/" + xsltParam.substring(toReplace.length);
print(" => " + newValue)
parameters.setValue("xslt", newValue);
zi.saveChanges();
done++;
}
else
{
print(" => ok")
}
})
print("...");
print(done + " services modifiés sur " + count)
if (done > 0)
{
print("PENSEZ A RECONSTRUIRE LE LIVE")
}
Migration des services
Suite à une modification d'API et de stockages des données, les services existants doivent être migrés. Exécutez le script sur la page dédiée à la migration des services.
Ne conservez pas les anciennes données indéxées (supprimez tout le contenu du "solr home" (sauf le dossier logs éventuellement), par défaut il se trouve dans solr/server/solr, puis copiez-collez les données par défaut issues de la livraison du ametys-solr-config-*.zip)
Après redémarrage du serveur Solr puis Ametys, lancez une indexation totale.