Skip to content

Commit

Permalink
chore(release): pull main into develop post release v1.69.1 (#3502)
Browse files Browse the repository at this point in the history
  • Loading branch information
krishna2020 authored Jun 25, 2024
2 parents 8129a06 + bdcc878 commit 86cebc1
Show file tree
Hide file tree
Showing 17 changed files with 1,361 additions and 8 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

### [1.69.1](https://github.com/rudderlabs/rudder-transformer/compare/v1.69.0...v1.69.1) (2024-06-25)


### Bug Fixes

* enhancement: introduce user model for one signal ([#3499](https://github.com/rudderlabs/rudder-transformer/issues/3499)) ([1c8e950](https://github.com/rudderlabs/rudder-transformer/commit/1c8e950f3d8789b33bba69a30c9eb21c40ce3d04))

## [1.69.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.68.2...v1.69.0) (2024-06-10)


Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rudder-transformer",
"version": "1.69.0",
"version": "1.69.1",
"description": "",
"homepage": "https://github.com/rudderlabs/rudder-transformer#readme",
"bugs": {
Expand Down
21 changes: 21 additions & 0 deletions src/v0/destinations/one_signal/config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const { getMappingConfig } = require('../../util');

const BASE_URL = 'https://onesignal.com/api/v1';
const BASE_URL_V2 = 'https://api.onesignal.com/apps/{{app_id}}/users';

const ENDPOINTS = {
IDENTIFY: {
Expand All @@ -16,13 +17,33 @@ const ENDPOINTS = {

const ConfigCategory = {
IDENTIFY: { name: 'OneSignalIdentifyConfig', endpoint: '/players' },
IDENTIFY_V2: { name: 'OneSignalIdentifyConfigV2' },
SUBSCRIPTION: { name: 'OneSignalSubscriptionConfig' },
};

const mappingConfig = getMappingConfig(ConfigCategory, __dirname);

// Used for User Model (V2)
const deviceTypesV2Enums = [
'iOSPush',
'email',
'sms',
'AndroidPush',
'HuaweiPush',
'FireOSPush',
'WindowsPush',
'macOSPush',
'ChromeExtensionPush',
'ChromePush',
'SafariLegacyPush',
'FirefoxPush',
'SafariPush',
];
module.exports = {
BASE_URL,
BASE_URL_V2,
ENDPOINTS,
ConfigCategory,
mappingConfig,
deviceTypesV2Enums,
};
54 changes: 54 additions & 0 deletions src/v0/destinations/one_signal/data/OneSignalIdentifyConfigV2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
[
{ "sourceKeys": "context.locale", "destKey": "properties.laguage", "required": false },
{ "sourceKeys": "context.ip", "destKey": "properties.ip", "required": false },
{ "sourceKeys": "context.timezone", "destKey": "properties.timezone_id", "required": false },
{ "sourceKeys": "context.location.latitude", "destKey": "properties.lat", "required": false },
{ "sourceKeys": "context.location.longitude", "destKey": "properties.long", "required": false },
{
"sourceKeys": "createdAt",
"destKey": "properties.created_at",
"sourceFromGenericMap": true,
"metadata": {
"type": "secondTimestamp"
},
"required": false
},
{
"sourceKeys": "createdAt",
"destKey": "properties.last_active",
"sourceFromGenericMap": true,
"metadata": {
"type": "secondTimestamp"
},
"required": false
},
{
"sourceKeys": [
"traits.country",
"context.traits.country",
"traits.address.country",
"context.traits.address.country"
],
"destKey": "properties.country",
"required": false
},
{
"sourceKeys": [
"traits.firstActive",
"context.traits.firstActive",
"traits.first_active",
"context.traits.first_active"
],
"metadata": {
"type": "secondTimestamp"
},
"destKey": "properties.first_active",
"required": false
},
{
"sourceKeys": "userIdOnly",
"destKey": "identity.external_id",
"sourceFromGenericMap": true,
"required": false
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{ "sourceKeys": "enabled", "destKey": "enabled", "required": false },
{ "sourceKeys": "notification_types", "destKey": "notification_types", "required": false },
{ "sourceKeys": "session_time", "destKey": "session_time", "required": false },
{ "sourceKeys": "session_count", "destKey": "session_count", "required": false },
{ "sourceKeys": "app_version", "destKey": "app_version", "required": false },
{ "sourceKeys": "test_type", "destKey": "test_type", "required": false }
]
9 changes: 8 additions & 1 deletion src/v0/destinations/one_signal/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const {
TransformationError,
InstrumentationError,
} = require('@rudderstack/integrations-lib');
const { process: processV2 } = require('./transformV2');
const { EventType } = require('../../../constants');
const { ConfigCategory, mappingConfig, BASE_URL, ENDPOINTS } = require('./config');
const {
Expand Down Expand Up @@ -186,10 +187,16 @@ const groupResponseBuilder = (message, { Config }) => {
};

const processEvent = (message, destination) => {
const { Config } = destination;
const { version, appId } = Config;
if (version === 'V2') {
// This version is used to direct the request to user centric model
return processV2(message, destination);
}
if (!message.type) {
throw new InstrumentationError('Event type is required');
}
if (!destination.Config.appId) {
if (!appId) {
throw new ConfigurationError('appId is a required field');
}
const messageType = message.type.toLowerCase();
Expand Down
159 changes: 159 additions & 0 deletions src/v0/destinations/one_signal/transformV2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
const get = require('get-value');
const {
ConfigurationError,
TransformationError,
InstrumentationError,
} = require('@rudderstack/integrations-lib');
const { EventType } = require('../../../constants');
const { ConfigCategory, mappingConfig, BASE_URL_V2 } = require('./config');
const {
defaultRequestConfig,
getFieldValueFromMessage,
constructPayload,
defaultPostRequestConfig,
removeUndefinedAndNullValues,
} = require('../../util');
const {
populateTags,
getProductPurchasesDetails,
getSubscriptions,
getOneSignalAliases,
} = require('./util');
const { JSON_MIME_TYPE } = require('../../util/constant');

const responseBuilder = (payload, Config) => {
const { appId } = Config;
if (payload) {
const response = defaultRequestConfig();
response.endpoint = `${BASE_URL_V2.replace('{{app_id}}', appId)}`;
response.headers = {
Accept: JSON_MIME_TYPE,
'Content-Type': JSON_MIME_TYPE,
};
response.method = defaultPostRequestConfig.requestMethod;
response.body.JSON = removeUndefinedAndNullValues(payload);
return response;
}
throw new TransformationError('Payload could not be populated due to wrong input');
};

/**
* This function is used for creating response for identify call, to create a new user or update an existing user.
* a responseArray for creating/updating user is being prepared.
* If the value of emailDeviceType/smsDeviceType(toggle in dashboard) is true, separate responses will also be created
* for new subscriptions to be added to user with email/sms as token.
* @param {*} message
* @param {*} param1
* @returns
*/
const identifyResponseBuilder = (message, { Config }) => {
// Populating the tags
const tags = populateTags(message);

const payload = constructPayload(message, mappingConfig[ConfigCategory.IDENTIFY_V2.name]);
if (!payload?.identity?.external_id) {
const alias = getOneSignalAliases(message);
if (Object.keys(alias).length === 0) {
throw new InstrumentationError('userId or any other alias is required for identify');
}
payload.identity = alias;
}
// Following check is to intialise properties object in case we don't get properties object from construct payload
if (!payload.properties) {
payload.properties = {};
}
payload.subscriptions = getSubscriptions(message, Config);
payload.properties.tags = tags;
return responseBuilder(removeUndefinedAndNullValues(payload), Config);
};

/**
* This function is used to build the response for track call and Group call.
* It is used to edit the OneSignal tags using external_id.
* It edits tags[event] as true for track call
* @param {*} message
* @param {*} param1
* @returns
*/
const trackOrGroupResponseBuilder = (message, { Config }, msgtype) => {
const { eventAsTags, allowedProperties } = Config;
const event = get(message, 'event');
const groupId = getFieldValueFromMessage(message, 'groupId');
// validation and adding tags for track and group call respectively
const tags = {};
const payload = { properties: {} };
if (msgtype === EventType.TRACK) {
if (!event) {
throw new InstrumentationError('Event is not present in the input payloads');
}
/* Populating event as true in tags.
eg. tags: {
"event_name": true
}
*/
tags[event] = true;
payload.properties.purchases = getProductPurchasesDetails(message);
}
if (msgtype === EventType.GROUP) {
if (!groupId) {
throw new InstrumentationError('groupId is required for group events');
}
tags.groupId = groupId;
}

const externalUserId = getFieldValueFromMessage(message, 'userIdOnly');
if (!externalUserId) {
const alias = getOneSignalAliases(message);
if (Object.keys(alias).length === 0) {
throw new InstrumentationError('userId or any other alias is required for track and group');
}
payload.identity = alias;
} else {
payload.identity = {
external_id: externalUserId,
};
}

// Populating tags using allowed properties(from dashboard)
const properties = get(message, 'properties');
if (properties && allowedProperties && Array.isArray(allowedProperties)) {
allowedProperties.forEach((item) => {
if (typeof properties[item.propertyName] === 'string') {
const tagName =
event && eventAsTags ? `${event}_${[item.propertyName]}` : item.propertyName;
tags[tagName] = properties[item.propertyName];
}
});
}
payload.properties.tags = tags;
return responseBuilder(removeUndefinedAndNullValues(payload), Config);
};

const processEvent = (message, destination) => {
if (!message.type) {
throw new InstrumentationError('Event type is required');
}
if (!destination.Config.appId) {
throw new ConfigurationError('appId is a required field');
}
const messageType = message.type.toLowerCase();
let response;
switch (messageType) {
case EventType.IDENTIFY:
response = identifyResponseBuilder(message, destination);
break;
case EventType.TRACK:
response = trackOrGroupResponseBuilder(message, destination, EventType.TRACK);
break;
case EventType.GROUP:
response = trackOrGroupResponseBuilder(message, destination, EventType.GROUP);
break;
default:
throw new InstrumentationError(`Message type ${messageType} is not supported`);
}
return response;
};

const process = (message, destination) => processEvent(message, destination);

module.exports = { process };
Loading

0 comments on commit 86cebc1

Please sign in to comment.