Skip to content

Commit

Permalink
Add audience lookup function
Browse files Browse the repository at this point in the history
  • Loading branch information
aashikam committed Dec 19, 2024
1 parent efa6a24 commit 80571d9
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
public class Constants {

public static final String PROPERTY_ACCESS_TOKEN = "_FB_ACCESS_TOKEN_";
public static final String HASHED_PAYLOAD = "HASHED_PAYLOAD";
public static final String ACCESS_TOKEN = "access_token";
public static final String PROPERTY_ERROR_CODE = "ERROR_CODE";
public static final String PROPERTY_ERROR_MESSAGE = "ERROR_MESSAGE";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
/*
* Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
*
* WSO2 LLC. 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.wso2.carbon.facebook.ads.connector;

import org.apache.synapse.MessageContext;
Expand All @@ -7,18 +25,17 @@
import org.json.JSONObject;

public class FacebookDataClassMediator extends AbstractMediator {
public static final String PROPERTIES = "properties";

@Override
public boolean mediate(MessageContext synCtx) {
String jsonString = (String) ConnectorUtils.lookupTemplateParamater(synCtx, "properties");
String jsonString = (String) ConnectorUtils.lookupTemplateParamater(synCtx, PROPERTIES);
if (jsonString == null || jsonString.isEmpty()) {
return true;
}

JSONArray inputArray = new JSONArray(jsonString);

JSONObject finalObj = FacebookDataProcessor.processData(inputArray);
synCtx.setProperty("HASHED_PAYLOAD", finalObj.toString());
synCtx.setProperty(Constants.HASHED_PAYLOAD, finalObj.toString());
return true;
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
/*
* Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
*
* WSO2 LLC. 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.wso2.carbon.facebook.ads.connector;

import java.security.MessageDigest;
Expand All @@ -7,6 +25,7 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.synapse.SynapseException;
import org.json.JSONArray;
import org.json.JSONObject;
import org.apache.commons.logging.Log;
Expand Down Expand Up @@ -96,6 +115,7 @@ class FacebookDataProcessor {
US_STATE_MAP.put("wyoming", "wy");
US_STATE_MAP.put("district of columbia", "dc");

// If the country is not present here, default to lowercase
COUNTRY_MAP.put("unitedstates", "us");
COUNTRY_MAP.put("us", "us");
COUNTRY_MAP.put("unitedkingdom", "gb");
Expand Down Expand Up @@ -161,7 +181,6 @@ static JSONObject processData(JSONArray inputArray) {
String finalValue = normalized.isEmpty() ? "" : (requiresHashing(field) ? hashIfNotAlreadyHashed(normalized) : normalized);
dataRow.put(finalValue);
}

dataArray.put(dataRow);
}

Expand Down Expand Up @@ -200,7 +219,7 @@ private static String getOccurrenceValue(JSONObject entry, String originalField,
externIdFields.add(key);
}
}
// Sort them to ensure deterministic order (by base key and numeric index)
// Sort them
externIdFields.sort((a, b) -> {
String baseA = a.replaceAll("\\.\\d+", "");
String baseB = b.replaceAll("\\.\\d+", "");
Expand Down Expand Up @@ -251,7 +270,8 @@ private static int getSuffixIndex(String key) {
try {
return Integer.parseInt(m.group(1));
} catch (NumberFormatException e) {
// ignore
log.error("Error occurred while getting suffix index: ", e);
throw new SynapseException("Error occurred while getting suffix index: " + e.getMessage(), e);
}
}
return 0;
Expand All @@ -276,12 +296,6 @@ private static boolean requiresHashing(String fieldName) {
!fieldName.equalsIgnoreCase("PAGE_SCOPED_USER_ID");
}

private static void printNormalization(String fieldName, String originalValue, String normalizedValue) {
System.out.println("Normalizing field: " + fieldName);
System.out.println("original = " + originalValue);
System.out.println("normalized = " + normalizedValue);
}

private static Map<String, String> parsePhoneMeta(String val) {
Map<String, String> meta = new HashMap<>();
Pattern p = Pattern.compile("(alreadyHasPhoneCode|countryCode|phoneCode|phoneNumber)\\s*:\\s*([^;]+)");
Expand All @@ -299,6 +313,7 @@ private static Map<String, String> parsePhoneMeta(String val) {
return meta;
}

// Normalize phone numbers
private static String normalizePhone(String val, String country) {
Map<String, String> meta = parsePhoneMeta(val);
if (meta.isEmpty()) {
Expand Down Expand Up @@ -341,15 +356,16 @@ private static String normalizePhone(String val, String country) {
}
}
}

return phoneNumber;
}
}

// Normalize the cities
private static String normalizeCity(String val) {
return val.replaceAll("[^a-z]", "");
}

// Normalize the states
private static String normalizeState(String val, String country) {
String clean = val.replaceAll("[^a-z]", "");
if ("us".equalsIgnoreCase(country)) {
Expand All @@ -364,6 +380,7 @@ private static String normalizeState(String val, String country) {
return clean;
}

// Normalize the gender
private static String normalizeGender(String val) {
Set<String> maleSynonyms = new HashSet<>(Arrays.asList("m", "male", "man", "boy"));
Set<String> femaleSynonyms = new HashSet<>(Arrays.asList("f", "female", "woman", "girl"));
Expand All @@ -376,6 +393,7 @@ private static String normalizeGender(String val) {
return "m";
}

// Normalize the countries
private static String normalizeCountry(String val) {
val = val.replaceAll("[^a-z]", "");
String countryCode = COUNTRY_MAP.get(val);
Expand All @@ -385,6 +403,7 @@ private static String normalizeCountry(String val) {
return val;
}

// Normalize the dob
private static String parseDOBToYYYYMMDD(String val) {
String[] parts = val.split("[/\\-–]+");
if (parts.length < 3) {
Expand Down Expand Up @@ -481,27 +500,21 @@ private static String normalizeDOBD(String val) {

private static String normalizeField(String fieldName, String value, String country) {
if (value == null) {
printNormalization(fieldName, "null", "");
return "";
}

String originalValue = value;
String val = value.trim().toLowerCase();

switch (fieldName) {
case "EMAIL":
printNormalization(fieldName, originalValue, val);
return val;

case "PHONE":
val = normalizePhone(val, country);
printNormalization(fieldName, originalValue, val);
return val;

case "FN":
case "LN":
val = val.replaceAll("[^\\p{L}]", "");
printNormalization(fieldName, originalValue, val);
return val;

case "ZIP":
Expand All @@ -512,51 +525,41 @@ private static String normalizeField(String fieldName, String value, String coun
val = val.substring(0, 5);
}
}
printNormalization(fieldName, originalValue, val);
return val;

case "CT":
val = normalizeCity(val);
printNormalization(fieldName, originalValue, val);
return val;

case "ST":
val = normalizeState(val, country);
printNormalization(fieldName, originalValue, val);
return val;

case "COUNTRY":
val = normalizeCountry(val);
printNormalization(fieldName, originalValue, val);
return val;

case "DOB":
val = normalizeDOB(val);
printNormalization(fieldName, originalValue, val);
return val;

case "DOBY":
val = normalizeDOBY(val);
printNormalization(fieldName, originalValue, val);
return val;

case "DOBM":
val = normalizeDOBM(val);
printNormalization(fieldName, originalValue, val);
return val;

case "DOBD":
val = normalizeDOBD(val);
printNormalization(fieldName, originalValue, val);
return val;

case "GEN":
val = normalizeGender(val);
printNormalization(fieldName, originalValue, val);
return val;

default:
printNormalization(fieldName, originalValue, val);
return val;
}
}
Expand All @@ -568,7 +571,7 @@ private static String hashString(String input) {
byte[] encodedhash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
return bytesToHex(encodedhash);
} catch (NoSuchAlgorithmException e) {
log.error("Error hashing string", e);
log.error("Error hashing string: " + input, e);
return "";
}
}
Expand All @@ -589,8 +592,4 @@ private static String hashIfNotAlreadyHashed(String input) {
}
return hashString(input);
}

static void unhashAndPrintFinalPayload(JSONObject finalObj) {
System.out.println(finalObj.toString(4));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
*
* WSO2 LLC. 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.wso2.carbon.facebook.ads.connector;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.synapse.MessageContext;
import org.apache.synapse.commons.json.JsonUtil;
import org.apache.synapse.mediators.AbstractMediator;
import org.apache.synapse.core.axis2.Axis2MessageContext;
import org.wso2.carbon.connector.core.util.ConnectorUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class FilterAudiencesByNameMediator extends AbstractMediator {

private static final Log log = LogFactory.getLog(FilterAudiencesByNameMediator.class);
public static final String FILTER_BY_NAME = "filterByName";
public static final String DATA = "data";
public static final String PAGING = "paging";

@Override
public boolean mediate(MessageContext synCtx) {
String filterByName = (String) ConnectorUtils.lookupTemplateParamater(synCtx, FILTER_BY_NAME);
if (filterByName == null || filterByName.trim().isEmpty()) {
log.warn("filterByName parameter is null or empty. Skipping filtering.");
return true;
}
try {
Axis2MessageContext axis2MessageContext = (Axis2MessageContext) synCtx;
org.apache.axis2.context.MessageContext axis2MC = axis2MessageContext.getAxis2MessageContext();

if (JsonUtil.hasAJsonPayload(axis2MC)) {
String jsonString = JsonUtil.jsonPayloadToString(axis2MC);
JsonObject jsonObject = JsonParser.parseString(jsonString).getAsJsonObject();
JsonArray dataArray = jsonObject.getAsJsonArray(DATA);
if (dataArray == null) {
log.warn("No audiences are found.");
return true;
}

JsonArray filteredData = new JsonArray();
for (JsonElement element : dataArray) {
if (element.isJsonObject()) {
JsonObject dataObj = element.getAsJsonObject();
JsonElement nameElement = dataObj.get("name");
if (nameElement != null && nameElement.isJsonPrimitive()) {
String name = nameElement.getAsString();
if (name.contains(filterByName)) {
filteredData.add(dataObj);
}
}
}
}

jsonObject.add(DATA, filteredData);

// Remove the "paging" section from the JSON object
if (jsonObject.has(PAGING)) {
jsonObject.remove(PAGING);
}

String filteredJsonString = jsonObject.toString();

// Set the filtered JSON back as the payload
JsonUtil.getNewJsonPayload(axis2MC, filteredJsonString, true, true);
} else {
log.warn("No JSON payload found in the message context.");
}
} catch (Exception e) {
log.error("Error while filtering JSON payload by name: " + filterByName, e);
return false;
}
return true;
}
}
12 changes: 0 additions & 12 deletions src/main/resources/functions/addUsersToAudience.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,6 @@
<property name="operationPath" value="/{custom_audience_id}/users"/>
<property name="pathParameters" value="customAudienceId,"/>
</class>

<!-- Log the hashed payload right after hashing is done -->
<log level="full">
<property name="hashed-payload" expression="get-property('HASHED_PAYLOAD')"/>
</log>

<!-- Construct the final payload using the payload factory -->
<payloadFactory media-type="json" template-type="freemarker">
<format><![CDATA[
${args.arg1}
Expand All @@ -44,11 +37,6 @@ ${args.arg1}
</args>
</payloadFactory>

<!-- Log again after the payload factory to confirm the final message body -->
<log level="full">
<property name="final-payload" expression="json-eval($.)"/>
</log>

<property name="DISABLE_CHUNKING" scope="axis2" type="STRING" value="true"/>
<property name="messageType" value="application/json" scope="axis2"/>
<property name="ContentType" value="application/json" scope="axis2"/>
Expand Down
Loading

0 comments on commit 80571d9

Please sign in to comment.