/******************************************************************************* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. *******************************************************************************/ package org.apache.ofbiz.sfa.vcard; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import org.apache.ofbiz.base.util.Debug; import org.apache.ofbiz.base.util.FileUtil; import org.apache.ofbiz.base.util.StringUtil; import org.apache.ofbiz.base.util.UtilGenerics; import org.apache.ofbiz.base.util.UtilMisc; import org.apache.ofbiz.base.util.UtilProperties; import org.apache.ofbiz.base.util.UtilValidate; import org.apache.ofbiz.entity.Delegator; import org.apache.ofbiz.entity.GenericEntityException; import org.apache.ofbiz.entity.GenericValue; import org.apache.ofbiz.entity.condition.EntityCondition; import org.apache.ofbiz.entity.condition.EntityOperator; import org.apache.ofbiz.entity.util.EntityQuery; import org.apache.ofbiz.entity.util.EntityUtilProperties; import org.apache.ofbiz.party.party.PartyHelper; import org.apache.ofbiz.party.party.PartyWorker; import org.apache.ofbiz.service.DispatchContext; import org.apache.ofbiz.service.GenericServiceException; import org.apache.ofbiz.service.LocalDispatcher; import org.apache.ofbiz.service.ServiceUtil; import ezvcard.Ezvcard; import ezvcard.io.text.VCardReader; import ezvcard.parameter.AddressType; import ezvcard.parameter.EmailType; import ezvcard.parameter.TelephoneType; import ezvcard.property.Address; import ezvcard.property.Email; import ezvcard.property.FormattedName; import ezvcard.property.StructuredName; import ezvcard.property.Telephone; public class VCard { public static final String module = VCard.class.getName(); public static final String resourceError = "MarketingUiLabels"; /** * import a vcard from byteBuffer. the reader use is ez-vcard, see official site https://github.com/mangstadt/ez-vcard/ * @param dctx * @param context * @return * @throws IOException */ public static Map<String, Object> importVCard(DispatchContext dctx, Map<String, ? extends Object> context) throws IOException { LocalDispatcher dispatcher = dctx.getDispatcher(); Delegator delegator = dctx.getDelegator(); Locale locale = (Locale) context.get("locale"); Map<String, Object> result = ServiceUtil.returnSuccess(); ByteBuffer byteBuffer = (ByteBuffer) context.get("infile"); byte[] inputByteArray = byteBuffer.array(); InputStream in = new ByteArrayInputStream(inputByteArray); Map<String, Object> serviceCtx = new HashMap<String, Object>(); boolean isGroup = false; List<Map<String, String>> partiesCreated = new ArrayList<Map<String,String>>(); List<Map<String, String>> partiesExist = new ArrayList<Map<String,String>>(); String partyName = ""; // TODO this is not used yet try (VCardReader vCardReader = new VCardReader(in)) { ezvcard.VCard vcard = null; while ((vcard = vCardReader.readNext()) != null) { //Todo create a generic service to resolve duplicate party FormattedName formattedName = vcard.getFormattedName(); if (formattedName != null) { String refCardId = formattedName.getValue(); GenericValue partyIdentification = EntityQuery.use(delegator).from("PartyIdentification").where("partyIdentificationTypeId", "VCARD_FN_ORIGIN", "idValue", refCardId).queryFirst(); if (partyIdentification != null) { partiesExist.add(UtilMisc.toMap("partyId", (String)partyIdentification.get("partyId"))); continue; } //TODO manage update } //check if it's already load isGroup = false; if (vcard.getKind() != null) isGroup = vcard.getKind().isGroup(); StructuredName structuredName = vcard.getStructuredName(); if (UtilValidate.isEmpty(structuredName)) continue; if (!isGroup) { serviceCtx.put("firstName", structuredName.getGiven()); serviceCtx.put("lastName", structuredName.getFamily()); partyName = structuredName.getGiven() + " " + structuredName.getFamily(); } // Resolve all postal Address for (Address address : vcard.getAddresses()) { boolean workAddress = false; for (AddressType addressType : address.getTypes()) { if (AddressType.PREF.equals(addressType) || AddressType.WORK.equals(addressType)) { workAddress = true; break; } } if (! workAddress) continue; serviceCtx.put("address1", address.getStreetAddressFull()); serviceCtx.put("city", address.getLocality()); serviceCtx.put("postalCode", address.getPostalCode()); GenericValue countryGeo = EntityQuery.use(delegator).from("Geo") .where(EntityCondition.makeCondition("geoTypeId", EntityOperator.EQUALS, "COUNTRY"), EntityCondition.makeCondition("geoName", EntityOperator.LIKE, address.getCountry())) .cache().queryFirst(); if (countryGeo != null) { serviceCtx.put("countryGeoId", countryGeo.get("geoId")); } GenericValue stateGeo = EntityQuery.use(delegator).from("Geo") .where(EntityCondition.makeCondition("geoTypeId", EntityOperator.EQUALS, "STATE"), EntityCondition.makeCondition("geoName", EntityOperator.LIKE, address.getRegion())) .cache().queryFirst(); if (stateGeo != null) { serviceCtx.put("stateProvinceGeoId", stateGeo.get("geoId")); } } int nbEmailAddr = (vcard.getEmails() != null) ? vcard.getEmails().size() : 0; for (Email email : vcard.getEmails()) { if (nbEmailAddr > 1) { boolean workEmail = false; for (EmailType emailType : email.getTypes()) { if (EmailType.PREF.equals(emailType) || EmailType.WORK.equals(emailType)) { workEmail = true; break; } } if (! workEmail) continue; } String emailAddr = email.getValue(); if (UtilValidate.isEmail(emailAddr)) { serviceCtx.put("emailAddress", emailAddr); } else { //TODO change uncorrect labellisation String emailFormatErrMsg = UtilProperties.getMessage(resourceError, "SfaImportVCardEmailFormatError", locale); vCardReader.close(); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "MarketingEmailFormatError", UtilMisc.toMap("firstName", structuredName.getGiven(), "lastName", structuredName.getFamily(), "emailFOrmatErrMsg", emailFormatErrMsg), locale)); } } int nbPhone = (vcard.getTelephoneNumbers() != null) ? vcard.getTelephoneNumbers().size() : 0; for (Telephone phone : vcard.getTelephoneNumbers()) { if (nbPhone > 1) { boolean workPhone = false; for (TelephoneType phoneType : phone.getTypes()) { if (TelephoneType.PREF.equals(phoneType) || TelephoneType.WORK.equals(phoneType)) { workPhone = true; break; } } if (! workPhone) continue; } String phoneAddr = phone.getText(); boolean internationalPhone = phoneAddr.startsWith("+") || phoneAddr.startsWith("00"); phoneAddr = StringUtil.removeNonNumeric(phoneAddr); int indexLocal = 0; if (internationalPhone) { indexLocal = 4; if (!phoneAddr.startsWith("00")) { phoneAddr = phoneAddr.concat("00"); } serviceCtx.put("areaCode", phoneAddr.substring(0, indexLocal)); } serviceCtx.put("contactNumber", phoneAddr.substring(indexLocal)); } /* TODO improve this part to manage party organization */ GenericValue userLogin = (GenericValue) context.get("userLogin"); serviceCtx.put("userLogin", userLogin); String serviceName = (String) context.get("serviceName"); Map<String, Object> serviceContext = UtilGenerics.cast(context.get("serviceContext")); if (UtilValidate.isNotEmpty(serviceContext)) { for (Map.Entry<String, Object> entry : serviceContext.entrySet()) { serviceCtx.put(entry.getKey(), entry.getValue()); } } Map<String, Object> resp = dispatcher.runSync(serviceName, serviceCtx); partiesCreated.add(UtilMisc.toMap("partyId", (String) resp.get("partyId"))); if (formattedName != null) { //store the origin creation Map<String, Object> createPartyIdentificationMap = dctx.makeValidContext("createPartyIdentification", "IN", context); createPartyIdentificationMap.put("partyId", resp.get("partyId")); createPartyIdentificationMap.put("partyIdentificationTypeId", "VCARD_FN_ORIGIN"); createPartyIdentificationMap.put("idValue", formattedName.getValue()); resp = dispatcher.runSync("createPartyIdentification", createPartyIdentificationMap); } } } catch (IOException | GenericEntityException | GenericServiceException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "SfaImportVCardError", UtilMisc.toMap("errorString", e.getMessage()), locale)); } result.put("partiesCreated", partiesCreated); result.put("partiesExist", partiesExist); return result; } public static Map<String, Object> exportVCard(DispatchContext dctx, Map<String, ? extends Object> context) { Delegator delegator = dctx.getDelegator(); String partyId = (String) context.get("partyId"); Locale locale = (Locale) context.get("locale"); File file = null; try { ezvcard.VCard vcard = new ezvcard.VCard(); StructuredName structuredName = new StructuredName(); GenericValue person = EntityQuery.use(delegator).from("Person").where("partyId", partyId).queryOne(); if (person != null) { if (UtilValidate.isNotEmpty(person.getString("firstName"))) structuredName.setGiven(person.getString("firstName")); if (UtilValidate.isNotEmpty(person.getString("lastName"))) structuredName.setFamily(person.getString("lastName")); vcard.setStructuredName(structuredName); } String fullName = PartyHelper.getPartyName(delegator, partyId, false); vcard.setFormattedName(fullName); GenericValue postalAddress = PartyWorker.findPartyLatestPostalAddress(partyId, delegator); if (postalAddress != null) { Address address = new Address(); address.setStreetAddress(postalAddress.getString("address1")); address.setLocality(postalAddress.getString("city")); address.setPostalCode(postalAddress.getString("postalCode")); GenericValue state = postalAddress.getRelatedOne("StateProvinceGeo", false); if (state != null) { address.setRegion(state.getString("geoName")); } GenericValue countryGeo = postalAddress.getRelatedOne("CountryGeo", false); if (countryGeo != null) { String country = postalAddress.getRelatedOne("CountryGeo", false).getString("geoName"); address.setCountry(country); address.getTypes().add(AddressType.WORK);; //TODO : this can be better set by checking contactMechPurposeTypeId } vcard.addAddress(address); } GenericValue telecomNumber = PartyWorker.findPartyLatestTelecomNumber(partyId, delegator); if (telecomNumber != null) { Telephone tel = new Telephone(telecomNumber.getString("areaCode") + telecomNumber.getString("contactNumber")); tel.getTypes().add(TelephoneType.WORK); vcard.addTelephoneNumber(tel); //TODO : this can be better set by checking contactMechPurposeTypeId } GenericValue emailAddress = PartyWorker.findPartyLatestContactMech(partyId, "EMAIL_ADDRESS", delegator); if (emailAddress != null && UtilValidate.isNotEmpty(emailAddress.getString("infoString"))) { vcard.addEmail(new Email(emailAddress.getString("infoString"))); } //TODO : convert to directdownload of a vcf file String saveToDirectory = EntityUtilProperties.getPropertyValue("sfa", "save.outgoing.directory", "", delegator); if (UtilValidate.isEmpty(saveToDirectory)) { saveToDirectory = System.getProperty("ofbiz.home"); } String saveToFilename = fullName + ".vcf"; file = FileUtil.getFile(saveToDirectory + "/" + saveToFilename); Ezvcard.write(vcard).go(file); } catch (FileNotFoundException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "SfaExportVCardErrorOpeningFile", UtilMisc.toMap("errorString", file.getAbsolutePath()), locale)); } catch (IOException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "SfaExportVCardErrorWritingFile", UtilMisc.toMap("errorString", file.getAbsolutePath()), locale)); } catch (GenericEntityException e) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "SfaExportVCardError", UtilMisc.toMap("errorString", e.getMessage()), locale)); } return ServiceUtil.returnSuccess(); } }