Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(release): pull main into develop post release v1.69.1 #3502

Merged
merged 3 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
};
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');

Check warning on line 37 in src/v0/destinations/one_signal/transformV2.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/one_signal/transformV2.js#L37

Added line #L37 was not covered by tests
};

/**
* 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 = {};

Check warning on line 63 in src/v0/destinations/one_signal/transformV2.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/one_signal/transformV2.js#L63

Added line #L63 was not covered by tests
}
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');

Check warning on line 137 in src/v0/destinations/one_signal/transformV2.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/one_signal/transformV2.js#L137

Added line #L137 was not covered by tests
}
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
Loading