Author: adrianc
Date: Sat Jun 27 13:42:43 2009 New Revision: 788972 URL: http://svn.apache.org/viewvc?rev=788972&view=rev Log: More work on the iCalendar integration. Still to do: report multi-status back to client, enforce SSL, create publish point screen. Modified: ofbiz/trunk/applications/workeffort/data/WorkEffortTypeData.xml ofbiz/trunk/applications/workeffort/script/org/ofbiz/workeffort/workeffort/WorkEffortSimpleServices.xml ofbiz/trunk/applications/workeffort/servicedef/services.xml ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalConverter.java Modified: ofbiz/trunk/applications/workeffort/data/WorkEffortTypeData.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/data/WorkEffortTypeData.xml?rev=788972&r1=788971&r2=788972&view=diff ============================================================================== --- ofbiz/trunk/applications/workeffort/data/WorkEffortTypeData.xml (original) +++ ofbiz/trunk/applications/workeffort/data/WorkEffortTypeData.xml Sat Jun 27 13:42:43 2009 @@ -226,4 +226,12 @@ <WebSite webSiteId="WORKEFFORT" siteName="Work Effort Manager" visualThemeSetId="BACKOFFICE"/> + <!-- iCalendar Data --> + <RoleType description="Calendar Member" hasTable="N" parentTypeId="CALENDAR_ROLE" roleTypeId="ICAL_MEMBER"/> + <ContactMechType contactMechTypeId="LDAP_ADDRESS" parentTypeId="ELECTRONIC_ADDRESS" hasTable="N" description="LDAP URL"/> + <ContactMechPurposeType contactMechPurposeTypeId="ICAL_URL" description="iCalendar URL"/> + <ContactMechTypePurpose contactMechPurposeTypeId="ICAL_URL" contactMechTypeId="EMAIL_ADDRESS"/> + <ContactMechTypePurpose contactMechPurposeTypeId="ICAL_URL" contactMechTypeId="LDAP_ADDRESS"/> + <ContactMechTypePurpose contactMechPurposeTypeId="ICAL_URL" contactMechTypeId="WEB_ADDRESS"/> + </entity-engine-xml> Modified: ofbiz/trunk/applications/workeffort/script/org/ofbiz/workeffort/workeffort/WorkEffortSimpleServices.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/script/org/ofbiz/workeffort/workeffort/WorkEffortSimpleServices.xml?rev=788972&r1=788971&r2=788972&view=diff ============================================================================== --- ofbiz/trunk/applications/workeffort/script/org/ofbiz/workeffort/workeffort/WorkEffortSimpleServices.xml (original) +++ ofbiz/trunk/applications/workeffort/script/org/ofbiz/workeffort/workeffort/WorkEffortSimpleServices.xml Sat Jun 27 13:42:43 2009 @@ -1480,11 +1480,7 @@ <entity-condition list="assignedParties" entity-name="WorkEffortPartyAssignment" filter-by-date="true"> <condition-list combine="and"> <condition-expr field-name="workEffortId" from-field="workEffortId"/> - <!-- DELEGATE has special meaning in publish properties - it's - another party in an ORGANIZER role, NOT a party whose work efforts - are included in a calendar. We need another role to define calendar - members. --> - <condition-expr field-name="roleTypeId" value="CAL_DELEGATE" operator="not-equals"/> + <condition-expr field-name="roleTypeId" value="ICAL_MEMBER"/> </condition-list> </entity-condition> <iterate entry="assignedParty" list="assignedParties"> @@ -1517,20 +1513,22 @@ <field-to-result field="workEfforts"/> </simple-method> - <simple-method method-name="getPartyICalUri" short-description="Get The Party iCalendar URI" login-required="false"> + <simple-method method-name="getPartyICalUrl" short-description="Get The Party iCalendar URL" login-required="false"> <!-- RFC 2445 4.8.4.1 and 4.8.4.3 Value must be a URI (4.3.3) --> - <!-- For now we just look for a primary email address. This could be expanded later. --> <set field="partyId" from-field="parameters.partyId"/> - <entity-condition list="emailAddresses" entity-name="PartyContactWithPurpose"> + <entity-condition list="contactMechs" entity-name="PartyContactWithPurpose"> <condition-list combine="and"> + <condition-list combine="or"> + <condition-expr field-name="contactMechPurposeTypeId" value="ICAL_URL"/> + <condition-expr field-name="contactMechPurposeTypeId" value="PRIMARY_EMAIL"/> + </condition-list> <condition-expr field-name="partyId" from-field="partyId"/> - <condition-expr field-name="contactMechPurposeTypeId" value="PRIMARY_EMAIL"/> <condition-expr field-name="purposeThruDate" from-field="null"/> </condition-list> + <order-by field-name="contactMechPurposeTypeId"/> </entity-condition> - <if-compare field="util:size(emailAddresses)" operator="not-equals" value="0" type="Integer"> - <set field="iCalUri" value="MAILTO:${emailAddresses[0].infoString}"/> - <field-to-result field="iCalUri"/> + <if-compare field="util:size(contactMechs)" operator="greater" value="0" type="Integer"> + <field-to-result field="iCalUrl" result-name="contactMechs[0].infoString"/> </if-compare> </simple-method> Modified: ofbiz/trunk/applications/workeffort/servicedef/services.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/servicedef/services.xml?rev=788972&r1=788971&r2=788972&view=diff ============================================================================== --- ofbiz/trunk/applications/workeffort/servicedef/services.xml (original) +++ ofbiz/trunk/applications/workeffort/servicedef/services.xml Sat Jun 27 13:42:43 2009 @@ -693,9 +693,9 @@ <attribute type="String" mode="IN" name="workEffortId" optional="false"/> <attribute type="List" mode="OUT" name="workEfforts"/> </service> - <service name="getPartyICalUri" engine="simple" auth="false" - location="component://workeffort/script/org/ofbiz/workeffort/workeffort/WorkEffortSimpleServices.xml" invoke="getPartyICalUri"> - <description>Get Party iCalendar URI</description> + <service name="getPartyICalUrl" engine="simple" auth="false" + location="component://workeffort/script/org/ofbiz/workeffort/workeffort/WorkEffortSimpleServices.xml" invoke="getPartyICalUrl"> + <description>Get Party iCalendar URL</description> <!-- No permission checking - the servlet handles that --> <attribute type="String" mode="IN" name="partyId" optional="false"/> <attribute type="String" mode="OUT" name="iCalUri" optional="true"/> Modified: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalConverter.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalConverter.java?rev=788972&r1=788971&r2=788972&view=diff ============================================================================== --- ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalConverter.java (original) +++ ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalConverter.java Sat Jun 27 13:42:43 2009 @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Set; +import javolution.util.FastList; import javolution.util.FastMap; import javolution.util.FastSet; @@ -86,6 +87,8 @@ "PRTYASGN_OFFERED", PartStat.TENTATIVE, "PRTYASGN_ASSIGNED", PartStat.ACCEPTED); protected static final Map<String, String> fromPartStatusMap = UtilMisc.toMap( "TENTATIVE", "PRTYASGN_OFFERED", "ACCEPTED", "PRTYASGN_ASSIGNED"); + protected static final Map<String, String> fromRoleMap = UtilMisc.toMap("ATTENDEE", "CAL_ATTENDEE", + "CONTACT", "CONTACT", "ORGANIZER", "CAL_ORGANIZER"); protected static VAlarm createAlarm(GenericValue workEffortEventReminder) { VAlarm alarm = null; @@ -118,20 +121,22 @@ serviceMap.put("workEffortTypeId", "VTODO".equals(component.getName()) ? "TASK" : "EVENT"); serviceMap.put("currentStatusId", "VTODO".equals(component.getName()) ? "CAL_NEEDS_ACTION" : "CAL_TENTATIVE"); serviceMap.put("partyId", ((GenericValue) context.get("userLogin")).get("partyId")); - serviceMap.put("roleTypeId", "CAL_ORGANIZER"); + serviceMap.put("roleTypeId", "CAL_OWNER"); serviceMap.put("statusId", "PRTYASGN_ASSIGNED"); Map<String, Object> serviceResult = invokeService("createWorkEffortAndPartyAssign", serviceMap, context); String workEffortId = (String) serviceResult.get("workEffortId"); if (workEffortId != null) { + replaceProperty(component.getProperties(), toXProperty(workEffortIdXPropName, workEffortId)); serviceMap.clear(); serviceMap.put("workEffortIdFrom", context.get("workEffortId")); serviceMap.put("workEffortIdTo", workEffortId); serviceMap.put("workEffortAssocTypeId", "WORK_EFF_DEPENDENCY"); serviceMap.put("fromDate", new Timestamp(System.currentTimeMillis())); serviceResult = invokeService("createWorkEffortAssoc", serviceMap, context); - if (!ServiceUtil.isError(serviceResult)) { - replaceProperty(component.getProperties(), toXProperty(workEffortIdXPropName, workEffortId)); + if (ServiceUtil.isError(serviceResult)) { + return; } + storePartyAssignments(workEffortId, component, context); } } @@ -244,6 +249,14 @@ return iCalObj.getValue(); } + protected static String fromUid(PropertyList propertyList) { + Uid iCalObj = (Uid) propertyList.getProperty(Uid.UID); + if (iCalObj == null) { + return null; + } + return iCalObj.getValue(); + } + protected static String fromXParameter(ParameterList parameterList, String parameterName) { if (parameterName == null) { return null; @@ -364,13 +377,16 @@ return calendar.toString(); } - protected static void getPartyPrimaryEmailAddress(Property property, GenericValue partyAssign, Map<String, Object> context) { + protected static void getPartyUrl(Property property, GenericValue partyAssign, Map<String, Object> context) { Map<String, ? extends Object> serviceMap = UtilMisc.toMap("partyId", partyAssign.get("partyId")); - Map<String, Object> resultMap = invokeService("getPartyICalUri", serviceMap, context); - String iCalUri = (String) resultMap.get("iCalUri"); - if (iCalUri != null) { + Map<String, Object> resultMap = invokeService("getPartyICalUrl", serviceMap, context); + String iCalUrl = (String) resultMap.get("iCalUrl"); + if (iCalUrl != null) { + if (!iCalUrl.contains(":") && iCalUrl.contains("@")) { + iCalUrl = "MAILTO:".concat(iCalUrl); + } try { - property.setValue(iCalUri); + property.setValue(iCalUrl); } catch (Exception e) { Debug.logError(e, "Error while setting party URI: ", module); } @@ -444,7 +460,7 @@ } protected static void loadPartyAssignment(Property property, GenericValue partyAssign, Map<String, Object> context) { - getPartyPrimaryEmailAddress(property, partyAssign, context); + getPartyUrl(property, partyAssign, context); if (UtilValidate.isEmpty(property.getValue())) { try { // RFC 2445 4.8.4.1 and 4.8.4.3 Value must be a URL @@ -501,7 +517,11 @@ replaceProperty(componentProps, toLocation(workEffort.getString("locationDesc"))); replaceProperty(componentProps, toStatus(workEffort.getString("currentStatusId"))); replaceProperty(componentProps, toSummary(workEffort.getString("workEffortName"))); - replaceProperty(componentProps, toUid(workEffort.getString("workEffortId"))); + Property uid = componentProps.getProperty(Uid.UID); + if (uid == null) { + // Don't overwrite UIDs created by calendar clients + replaceProperty(componentProps, toUid(workEffort.getString("workEffortId"))); + } replaceProperty(componentProps, toXProperty(workEffortIdXPropName, workEffort.getString("workEffortId"))); } @@ -580,6 +600,15 @@ map.put(key, value); } + protected static void setPartyIdFromUrl(Property property, Map<String, Object> context) { + Map<String, ? extends Object> serviceMap = UtilMisc.toMap("address", property.getValue(), "caseInsensitive", "Y"); + Map<String, Object> resultMap = invokeService("findPartyFromEmailAddress", serviceMap, context); + String partyId = (String) resultMap.get("partyId"); + if (partyId != null) { + replaceParameter(property.getParameters(), toXParameter(partyIdXParamName, partyId)); + } + } + protected static void setWorkEffortServiceMap(Component component, Map<String, Object> serviceMap) { PropertyList propertyList = component.getProperties(); setMapElement(serviceMap, "scopeEnumId", fromClazz(propertyList)); @@ -591,6 +620,7 @@ setMapElement(serviceMap, "priority", fromPriority(propertyList)); setMapElement(serviceMap, "currentStatusId", fromStatus(propertyList)); setMapElement(serviceMap, "workEffortName", fromSummary(propertyList)); + setMapElement(serviceMap, "universalId", fromUid(propertyList)); if ("VTODO".equals(component.getName())) { setMapElement(serviceMap, "actualCompletionDate", fromCompleted(propertyList)); setMapElement(serviceMap, "percentComplete", fromPercentComplete(propertyList)); @@ -626,9 +656,7 @@ } String workEffortId = fromXProperty(calendar.getProperties(), workEffortIdXPropName); if (workEffortId == null) { - // TODO: Create new publish point - Debug.logWarning("Warning: Not an OFBiz calendar: \r\n" + calendar, module); - return; + workEffortId = (String) context.get("workEffortId"); } if (!workEffortId.equals(context.get("workEffortId"))) { Debug.logWarning("Spoof attempt: received calendar workEffortId " + workEffortId + @@ -658,8 +686,18 @@ for (Component component : components) { if (Component.VEVENT.equals(component.getName()) || Component.VTODO.equals(component.getName())) { workEffortId = fromXProperty(component.getProperties(), workEffortIdXPropName); + if (workEffortId == null) { + Property uid = component.getProperty(Uid.UID); + if (uid != null) { + GenericValue workEffort = EntityUtil.getFirst(delegator.findByAnd("WorkEffort", UtilMisc.toMap("universalId", uid.getValue()))); + if (workEffort != null) { + workEffortId = workEffort.getString("workEffortId"); + } + } + } if (workEffortId != null) { if (validWorkEfforts.contains(workEffortId)) { + replaceProperty(component.getProperties(), toXProperty(workEffortIdXPropName, workEffortId)); storeWorkEffort(component, context); } else { Debug.logWarning("Spoof attempt: unrelated workEffortId " + workEffortId + @@ -680,6 +718,47 @@ } } + @SuppressWarnings("unchecked") + protected static void storePartyAssignments(String workEffortId, Component component, Map<String, Object> context) { + Map<String, Object> serviceMap = FastMap.newInstance(); + List<Property> partyList = FastList.newInstance(); + partyList.addAll(component.getProperties("ATTENDEE")); + partyList.addAll(component.getProperties("CONTACT")); + partyList.addAll(component.getProperties("ORGANIZER")); + for (Property property : partyList) { + String partyId = fromXParameter(property.getParameters(), partyIdXParamName); + if (partyId == null) { + serviceMap.clear(); + String address = property.getValue(); + if (address.toUpperCase().startsWith("MAILTO:")) { + address = address.substring(7); + } + serviceMap.put("address", address); + Map<String, Object> result = invokeService("findPartyFromEmailAddress", serviceMap, context); + partyId = (String) result.get("partyId"); + if (partyId == null) { + continue; + } + replaceParameter(property.getParameters(), toXParameter(partyIdXParamName, partyId)); + } + serviceMap.clear(); + serviceMap.put("workEffortId", workEffortId); + serviceMap.put("partyId", partyId); + serviceMap.put("roleTypeId", fromRoleMap.get(property.getName())); + GenericDelegator delegator = (GenericDelegator) context.get("delegator"); + List<GenericValue> assignments = null; + try { + assignments = EntityUtil.filterByDate(delegator.findByAnd("WorkEffortPartyAssignment", serviceMap)); + if (assignments.size() == 0) { + serviceMap.put("statusId", "PRTYASGN_OFFERED"); + serviceMap.put("fromDate", new Timestamp(System.currentTimeMillis())); + invokeService("assignPartyToWorkEffort", serviceMap, context); + } + } catch (GenericEntityException e) { + } + } + } + protected static void storeWorkEffort(Component component, Map<String, Object> context) throws GenericEntityException, GenericServiceException { PropertyList propertyList = component.getProperties(); String workEffortId = fromXProperty(propertyList, workEffortIdXPropName); @@ -695,12 +774,14 @@ serviceMap.put("workEffortId", workEffortId); setWorkEffortServiceMap(component, serviceMap); invokeService("updateWorkEffort", serviceMap, context); + storePartyAssignments(workEffortId, component, context); } @SuppressWarnings("unchecked") protected static void toCalendarComponent(ComponentList components, GenericValue workEffort, Map<String, Object> context) throws GenericEntityException { GenericDelegator delegator = workEffort.getDelegator(); String workEffortId = workEffort.getString("workEffortId"); + String workEffortUid = workEffort.getString("universalId"); String workEffortTypeId = workEffort.getString("workEffortTypeId"); GenericValue typeValue = delegator.findOne("WorkEffortType", UtilMisc.toMap("workEffortTypeId", workEffortTypeId), true); boolean isTask = false; @@ -724,6 +805,11 @@ newComponent = false; break; } + Property uid = result.getProperty(Uid.UID); + if (uid != null && uid.getValue().equals(workEffortUid)) { + newComponent = false; + break; + } } if (isTask) { VToDo toDo = null; |
Free forum by Nabble | Edit this page |