Lien d'une image provenant d'un attribut d'objet métier dans un mail

Request description

Bonjour, nous rencontrons des difficultés sur le lien d’une image provenant d’un attribut d’objet métier dans un e-mail, ce qui me laisse à penser que je ne m’y prends probablement pas de la bonne façon.

Voici ce que j’ai constaté :
Le logo que j’essaie d’obtenir est un attribut image de l’objet métier CrbPcaRefEpci. Je cherche l’instance adéquate et j’essaie d’ajouter l’image au corps de mon mail.

	public static String sendMailTest(ObjectDB demande){
		String mailBody="";
		MailTool mailer = new MailTool(demande.getGrant());
		
		mailer.setFrom("passcommerce@bretagne.bzh");
		mailer.setSubject("TEST PCA MAIL");
		
		mailBody="<HTML><BODY style='background-color: #f7f7f7;margin-left:60px;padding-top:0; font-family:Trebuchet MS Regular; font-size:12px; color:black';>";	
		mailBody += "<div style='font-size:12px;max-width:540;background-color: #ffffff;'>";

		MailImage logoEpci = null;
		ObjectDB refEpciTmp = demande.getGrant().getTmpObject("CrbPcaRefEpci");
		refEpciTmp.resetFilters();
		refEpciTmp.resetValues();
		refEpciTmp.setFieldFilter("pcaRefEpciSiren",demande.getFieldValue("pcaDemandeEpciSiren"));
		for(String[] rowEcpi : refEpciTmp.search()) {
			refEpciTmp.setValues(rowEcpi);
			logoEpci=mailer.getMail().documentImage(refEpciTmp,refEpciTmp.getField("pcaRefEpciLogo"));
		
			if (logoEpci!=null) {
				String idLogoEpci=mailer.addImage(logoEpci);
				mailBody+="<img src=\"cid:"+idLogoEpci+"\" />";
			}
		}
		mailBody +="</div></BODY></HTML>";
		
		mailer.setBody(mailBody);		
		mailer.addRcpt(getRcpt(demande,"accuseEnvoiLi_DEMANDEUR"));

		try {
			mailer.send();
			return "OK";
		} catch (Exception e) {
			return Message.formatSimpleError("Erreur d'envoi de mail" + e.getMessage());	
		}
	}

Dans cette configuration, documentImage retourne null, et donc l’intégration ne fonctionne pas.

Ensuite pour tester j’ai tenté de retrouver directement l’image avec getDocument sur l’attribut de l’objet CrbPcaRefEpci :

	public static String sendMailTest(ObjectDB demande){
		String mailBody="";
		MailTool mailer = new MailTool(demande.getGrant());
		
		mailer.setFrom("passcommerce@bretagne.bzh");
		mailer.setSubject("TEST PCA MAIL");
		
		mailBody="<HTML><BODY style='background-color: #f7f7f7;margin-left:60px;padding-top:0; font-family:Trebuchet MS Regular; font-size:12px; color:black';>";	
		mailBody += "<div style='font-size:12px;max-width:540;background-color: #ffffff;'>";
		
		MailImage logoEpci = null;
		ObjectDB refEpciTmp = demande.getGrant().getTmpObject("CrbPcaRefEpci");
		refEpciTmp.resetFilters();
		refEpciTmp.resetValues();
		refEpciTmp.setFieldFilter("pcaRefEpciSiren",demande.getFieldValue("pcaDemandeEpciSiren"));
		for(String[] rowEcpi : refEpciTmp.search()) {
			refEpciTmp.setValues(rowEcpi);
				
			DocumentDB logoDoc = refEpciTmp.getField("pcaRefEpciLogo").getDocument(demande.getGrant());
			logoEpci=mailer.getMail().documentImage(refEpciTmp,refEpciTmp.getField("pcaRefEpciLogo"));
		
			if (logoEpci!=null) {
				String idLogoEpci=mailer.addImage(logoEpci);
				mailBody+="<img src=\"cid:"+idLogoEpci+"\" />";
			}
		}
		mailBody +="</div></BODY></HTML>";
		
		mailer.setBody(mailBody);		
		mailer.addRcpt(getRcpt(demande,"accuseEnvoiLi_DEMANDEUR"));

		try {
			mailer.send();
			return "OK";
		} catch (Exception e) {
			return Message.formatSimpleError("Erreur d'envoi de mail" + e.getMessage());	
		}
		
	}

Et dans cette situation, non seulement l’appel à getDocument retourne bien le document, mais ensuite documentImage parvient également à lier l’image, alors qu’a priori je ne vois aucun lien direct entre les deux.

Je soupçonne un problème d’habilitation, mais si c’est le cas je ne suis pas sûr de comment le régler. Et même si le code de la deuxième version fonctionne, ça ne me parait pas logique et donc potentiellement amené à ne plus fonctionner, ou créer d’autres problèmes.

Voyez-vous ce qui pourrait expliquer cela?

Merci

Technical information

Instance /health

[Platform]
Status=OK
Version=5.2.36
BuiltOn=2023-04-05 18:35
Git=5.2/966009edb80e3e6fad18685d6ef8131b63725d28
Encoding=UTF-8
EndpointIP=127.0.0.1
EndpointURL=https://dev-sim:10773/passcommerce
TimeZone=Europe/Paris
SystemDate=2023-04-14 11:07:03

[Application]
ApplicationVersion=1.0.0
ContextPath=/passcommerce
ContextURL=http://passcommerce.dev-sim.cr-bretagne.fr/passcommerce
ActiveSessions=3
TotalUsers=20
EnabledUsers=18
LastLoginDate=2023-04-14 11:02:38

[Server]
ServerInfo=Apache Tomcat/9.0.73
ServerType=WEB
ServerActiveSessions=0
ServerSessionTimeout=30

[OS]
Name=Linux
Architecture=amd64
Version=3.10.0-1062.9.1.el7.x86_64
SystemEncoding=UTF-8

[Disk]
DiskFree=17649
DiskUsable=15229
DiskTotal=57303

[JavaVM]
Version=11.0.6
Vendor=Oracle Corporation
VMName=OpenJDK 64-Bit Server VM
VMVersion=11.0.6+10-LTS
ScriptEngine=rhino
ScriptEngineVersion=Rhino 1.7.13 2020 09 02
HeapFree=122179
HeapSize=417792
HeapMaxSize=524288
TotalFreeSize=228675

[Cache]
ObjectCache=136
ObjectCacheMax=10000
ObjectCacheRatio=1
ProcessCache=11
ProcessCacheMax=10000
ProcessCacheRatio=0
APIGrantCache=0
APIGrantCacheMax=1000
APIGrantRatio=0

[Database]
Vendor=2
ProductName=MySQL
ProductVersion=5.5.5-10.2.9-MariaDB-10.2.9+maria~stretch
DriverName=MySQL Connector/J
DriverVersion=mysql-connector-j-8.0.32 (Revision: fa4912a849140828e48162a2c396c8df0091bed7)
DBDate=2023-04-14 11:07:03
DBDateOffset=0
DBPatchLevel=5;P02;c49a0b5b4201087167f67be076255c60
UsingBLOBs=true

[Healthcheck]
Date=2023-04-14 11:07:03
ElapsedTime=11

Cette méthode copie le tuple “rowEcpi” par valeurs dans les Fields, mais ne charge pas le document en mémoire, le champ Logo contient alors que l’ID du document.

Cette méthode getDocument force le chargement du document en mémoire d’après la valeur du champ = le row_id du document.
Cela explique que le documentImage parvient ensuite à mettre la pièce jointe non null dans l’email.

Bref votre code me semble correct.

La classe MailTool contient des méthodes ad hoc pour gérer les attributs documents sans avoir besoin de descendre “bas” dans les APIs de l’objet : MailTool pour attacher des documents et MailTool pour inliner des images

J’utilise MailTool.addImage(MailImage), avec un Mail.documentImage pour obtenir le MailImage. Effectivement je n’avais pas vu MailTool.addImage(ObjectDB, ObjectField) qui est un peu plus direct.

Cependant je viens de tester, et avec celle-ci aussi j’ai besoin du getDocument précédent, sinon l’image n’est pas ajoutée au mail non plus.

	DocumentDB logoDoc = refEpciTmp.getField("pcaRefEpciLogo").getDocument(demande.getGrant());
	String idLogoEpci=mailer.addImage(refEpciTmp,refEpciTmp.getField("pcaRefEpciLogo") );
	mailBody+="<img src=\"cid:"+idLogoEpci+"\" />";

Ceci dit, si vous me confirmez que c’est bien comme ça qu’il faut faire, pas de problème.

Je ne vois pas pourquoi le addImage aurait besoin d’autre chose… je vais refaire des tests pour vérifier…

Dans quel contexte est appelé votre méthode ? Le pb est peut être plutôt à ce niveau

La méthode est dans un code partagé, appelé normalement depuis une action après transition d’état, mais là juste depuis une méthode test unitaire pour les tests (on a le même problème dans les 2 cas).

Il y a peut-être des choses un peu bizarres au niveau habilitation, nous avons une autre image ressource globale qui ne se chargeait pas avec le grant MailTool() par défaut, ce pourquoi nous lui affectons le grant de l’objet métier sur lequel porte le process.

MailTool mailer = new MailTool(demande.getGrant());

Ceci dit au final le getDocument qu’on a dû ajouter utilise exactement le même :

DocumentDB logoDoc = refEpciTmp.getField("pcaRefEpciLogo").getDocument(demande.getGrant());

Dans le cadre d’un test unitaire il faut faire un select explicite sur un record pour qu’un record soit en mémoire lors de l’appel sinon ça peut faire n’importe quoi.

Dans le cadre d’une transition d’état si vous passez bien l’objet this le record courant est bien en mémoire et ça devrait faire ce qu’il faut.

Je suis en train d’ajouter un exemple de ce type à la démo (via appel d’action), je vous dirai si je vois un pb.

Dans la transition d’état on passe bien this à la méthode :

String mailSend=PCA_sendMail.sendMail(this,"accuseEnvoiLi_DEMANDEUR");

Dans le unitTests je fais un search pour passer un objet spécifique à la méthode :

	public String unitTests() {
		AppLog.info(getClass(), "unitTests", "==========TEST==========", getGrant());
		ObjectDB demandeTmp=getGrant().getTmpObject("CrbPcaDemande");
		demandeTmp.resetFilters();
		demandeTmp.resetValues();
		demandeTmp.setFieldFilter("pcaDemandeNum","2023-0054");
		for (String[] rowDemande : demandeTmp.search()){
			demandeTmp.setValues(rowDemande);
			PCA_sendMail.sendMail(demandeTmp,"accuseEnvoiLi_DEMANDEUR");
			PCA_sendMail.sendMailTest(demandeTmp);
		}
		return "Fin des tests";
	}

Par contre ce n’est pas dans cet objet-ci qu’on va chercher l’attribut image, c’est un attribut de CrbPcaRefEpci, d’où le search sur cet objet dans la méthode d’envoi du mail.

(Dans la transition la méthode appelée est sendMail, mais sendMailTest fait la même chose, j’ai juste essayé de n’y laisser que la partie qui posait problème pour l’analyse).

Voici un exemple qui marche (hors contexte de test unitaire que je vais ajouter): module-demo/src/com/simplicite/objects/Demo/DemoProduct.java at master · simplicitesoftware/module-demo · GitHub => cf. la méthode sendMail appelée par une action:

	@BusinessObjectAction
	public String sendEmail(Action a) {
		try {
			MailTool mt = new MailTool(getGrant());
			mt.addRcpt(getGrant().getEmail());
			String ref = getFieldValue("demoPrdReference");
			mt.setSubject(getName() + " " + ref);
			mt.addAttach(this, getField("demoPrdBrochure"));
			String picCid = mt.addImage(this, getField("demoPrdPicture"));
			mt.setBody(
				"<h1>" + Tool.toHTML(ref) + "</h1>" +
				"<img src=\"cid:" + picCid +  "\"/>" +
				"<h3>" + Tool.toHTML(getFieldValue("demoPrdName")) + "</h3>" +
				"<h5>" + Tool.toHTML(getFieldValue("demoPrdDescription")) + "</h5>" +
				"<div>" + getFieldValue("demoPrdDocumentation") + "</div>"
			);
			mt.send();
			return Message.formatSimpleInfo("OK");
		} catch (Exception e) {
			AppLog.error(null, e, getGrant());
			return Message.formatSimpleError(e.getMessage());
		}
	}

J’appelle l’action:

Je reçois le mail suivant:

Image inlinée + doc en PJ

Effectivement dans le contexte d’un test unitaire il manque l’image et la PJ dans le mail:

	/** Product's stock increment test */
	@Test
	public void testSendMail() {
		Grant sys = Grant.getSystemAdmin();
		try {
			ObjectDB prd = sys.getObject("test_DemoProduct", "DemoProduct");
			prd.setValues(prd.getTool().search(new JSONObject().put("demoPrdReference", "REF001")).get(0), true);
			AppLog.info("Send email acton result: " + prd.invokeAction("DEMO_PRD_EMAIL"), sys);
		} catch (Exception e) {
			fail(e.getMessage());
		}
	}

On va regarder mais dans le cas de votre transition d’état il ne devrait pas y avoir le pb.

OK c’est vu et corrigé pour le cas des tests unitaires (ou autre usage indirect du même genre = search/select basique sans chargement des docs infos du record).

Ce sera dans la version 5.2.37 livrée d’ici lundi

Je confirme, ça marche pour moi, y compris pour l’objet obtenu par search.

Merci