Add support for more audience fields. (#4145)
* Add support for more audience fields. * Only update audience when defined audience_id.
This commit is contained in:
committed by
Florent Vilmart
parent
9fbb5e29e8
commit
4dce3bd63c
@@ -285,7 +285,7 @@ describe('AudiencesRouter', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it_exclude_dbs(['postgres'])('should not log error with legacy parse.com times_used and _last_used fields', (done) => {
|
||||
it_exclude_dbs(['postgres'])('should support legacy parse.com audience fields', (done) => {
|
||||
const database = (new Config(Parse.applicationId)).database.adapter.database;
|
||||
const now = new Date();
|
||||
Parse._request('POST', 'push_audiences', { name: 'My Audience', query: JSON.stringify({ deviceType: 'ios' })}, { useMasterKey: true })
|
||||
@@ -306,13 +306,12 @@ describe('AudiencesRouter', () => {
|
||||
expect(error).toEqual(null)
|
||||
expect(rows[0]['times_used']).toEqual(1);
|
||||
expect(rows[0]['_last_used']).toEqual(now);
|
||||
Parse._request('GET', 'push_audiences', {}, {useMasterKey: true})
|
||||
.then((results) => {
|
||||
expect(results.results.length).toEqual(1);
|
||||
expect(results.results[0].name).toEqual('My Audience');
|
||||
expect(results.results[0].query.deviceType).toEqual('ios');
|
||||
expect(results.results[0].times_used).toEqual(undefined);
|
||||
expect(results.results[0]._last_used).toEqual(undefined);
|
||||
Parse._request('GET', 'push_audiences/' + audience.objectId, {}, {useMasterKey: true})
|
||||
.then((audience) => {
|
||||
expect(audience.name).toEqual('My Audience');
|
||||
expect(audience.query.deviceType).toEqual('ios');
|
||||
expect(audience.timesUsed).toEqual(1);
|
||||
expect(audience.lastUsed).toEqual(now.toISOString());
|
||||
done();
|
||||
})
|
||||
.catch((error) => { done.fail(error); })
|
||||
@@ -320,4 +319,19 @@ describe('AudiencesRouter', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to search on audiences', (done) => {
|
||||
Parse._request('POST', 'push_audiences', { name: 'neverUsed', query: JSON.stringify({ deviceType: 'ios' })}, { useMasterKey: true })
|
||||
.then(() => {
|
||||
const query = {"timesUsed": {"$exists": false}, "lastUsed": {"$exists": false}};
|
||||
Parse._request('GET', 'push_audiences?order=-createdAt&limit=1', {where: query}, {useMasterKey: true})
|
||||
.then((results) => {
|
||||
expect(results.results.length).toEqual(1);
|
||||
const audience = results.results[0];
|
||||
expect(audience.name).toEqual("neverUsed");
|
||||
done();
|
||||
})
|
||||
.catch((error) => { done.fail(error); })
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1000,6 +1000,95 @@ describe('PushController', () => {
|
||||
}).catch(done.fail);
|
||||
});
|
||||
|
||||
it('should update audiences', (done) => {
|
||||
var pushAdapter = {
|
||||
send: function(body, installations) {
|
||||
return successfulTransmissions(body, installations);
|
||||
},
|
||||
getValidPushTypes: function() {
|
||||
return ["ios"];
|
||||
}
|
||||
}
|
||||
|
||||
var config = new Config(Parse.applicationId);
|
||||
var auth = {
|
||||
isMaster: true
|
||||
}
|
||||
|
||||
var audienceId = null;
|
||||
var now = new Date();
|
||||
var timesUsed = 0;
|
||||
|
||||
const where = {
|
||||
'deviceType': 'ios'
|
||||
}
|
||||
spyOn(pushAdapter, 'send').and.callThrough();
|
||||
var pushController = new PushController();
|
||||
reconfigureServer({
|
||||
push: { adapter: pushAdapter }
|
||||
}).then(() => {
|
||||
var installations = [];
|
||||
while (installations.length != 5) {
|
||||
const installation = new Parse.Object("_Installation");
|
||||
installation.set("installationId", "installation_" + installations.length);
|
||||
installation.set("deviceToken","device_token_" + installations.length)
|
||||
installation.set("badge", installations.length);
|
||||
installation.set("originalBadge", installations.length);
|
||||
installation.set("deviceType", "ios");
|
||||
installations.push(installation);
|
||||
}
|
||||
return Parse.Object.saveAll(installations);
|
||||
}).then(() => {
|
||||
// Create an audience
|
||||
const query = new Parse.Query("_Audience");
|
||||
query.descending("createdAt");
|
||||
query.equalTo("query", JSON.stringify(where));
|
||||
const parseResults = (results) => {
|
||||
if (results.length > 0) {
|
||||
audienceId = results[0].id;
|
||||
timesUsed = results[0].get('timesUsed');
|
||||
if (!isFinite(timesUsed)) {
|
||||
timesUsed = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
const audience = new Parse.Object("_Audience");
|
||||
audience.set("name", "testAudience")
|
||||
audience.set("query", JSON.stringify(where));
|
||||
return Parse.Object.saveAll(audience).then(() => {
|
||||
return query.find({ useMasterKey: true }).then(parseResults);
|
||||
});
|
||||
}).then(() => {
|
||||
var body = {
|
||||
data: { alert: 'hello' },
|
||||
audience_id: audienceId
|
||||
}
|
||||
return pushController.sendPush(body, where, config, auth)
|
||||
}).then(() => {
|
||||
// Wait so the push is completed.
|
||||
return new Promise((resolve) => { setTimeout(() => { resolve(); }, 1000); });
|
||||
}).then(() => {
|
||||
expect(pushAdapter.send.calls.count()).toBe(1);
|
||||
const firstCall = pushAdapter.send.calls.first();
|
||||
expect(firstCall.args[0].data).toEqual({
|
||||
alert: 'hello'
|
||||
});
|
||||
expect(firstCall.args[1].length).toBe(5);
|
||||
}).then(() => {
|
||||
// Get the audience we used above.
|
||||
const query = new Parse.Query("_Audience");
|
||||
query.equalTo("objectId", audienceId);
|
||||
return query.find({ useMasterKey: true })
|
||||
}).then((results) => {
|
||||
const audience = results[0];
|
||||
expect(audience.get('query')).toBe(JSON.stringify(where));
|
||||
expect(audience.get('timesUsed')).toBe(timesUsed + 1);
|
||||
expect(audience.get('lastUsed')).not.toBeLessThan(now);
|
||||
}).then(() => {
|
||||
done();
|
||||
}).catch(done.fail);
|
||||
});
|
||||
|
||||
describe('pushTimeHasTimezoneComponent', () => {
|
||||
it('should be accurate', () => {
|
||||
expect(PushController.pushTimeHasTimezoneComponent('2017-09-06T17:14:01.048Z'))
|
||||
|
||||
@@ -212,7 +212,7 @@ afterEach(function(done) {
|
||||
} else {
|
||||
// Other system classes will break Parse.com, so make sure that we don't save anything to _SCHEMA that will
|
||||
// break it.
|
||||
return ['_User', '_Installation', '_Role', '_Session', '_Product'].indexOf(className) >= 0;
|
||||
return ['_User', '_Installation', '_Role', '_Session', '_Product', '_Audience'].indexOf(className) >= 0;
|
||||
}
|
||||
}});
|
||||
});
|
||||
|
||||
@@ -10,6 +10,8 @@ const transformKey = (className, fieldName, schema) => {
|
||||
case 'createdAt': return '_created_at';
|
||||
case 'updatedAt': return '_updated_at';
|
||||
case 'sessionToken': return '_session_token';
|
||||
case 'lastUsed': return '_last_used';
|
||||
case 'timesUsed': return 'times_used';
|
||||
}
|
||||
|
||||
if (schema.fields[fieldName] && schema.fields[fieldName].__type == 'Pointer') {
|
||||
@@ -77,6 +79,16 @@ const transformKeyValueForUpdate = (className, restKey, restValue, parseFormatSc
|
||||
case '_rperm':
|
||||
case '_wperm':
|
||||
return {key: key, value: restValue};
|
||||
case 'lastUsed':
|
||||
case '_last_used':
|
||||
key = '_last_used';
|
||||
timeField = true;
|
||||
break;
|
||||
case 'timesUsed':
|
||||
case 'times_used':
|
||||
key = 'times_used';
|
||||
timeField = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((parseFormatSchema.fields[key] && parseFormatSchema.fields[key].type === 'Pointer') || (!parseFormatSchema.fields[key] && restValue && restValue.__type == 'Pointer')) {
|
||||
@@ -200,6 +212,14 @@ function transformQueryKeyValue(className, key, value, schema) {
|
||||
return {key: '$or', value: value.map(subQuery => transformWhere(className, subQuery, schema))};
|
||||
case '$and':
|
||||
return {key: '$and', value: value.map(subQuery => transformWhere(className, subQuery, schema))};
|
||||
case 'lastUsed':
|
||||
if (valueAsDate(value)) {
|
||||
return {key: '_last_used', value: valueAsDate(value)}
|
||||
}
|
||||
key = '_last_used';
|
||||
break;
|
||||
case 'timesUsed':
|
||||
return {key: 'times_used', value: value};
|
||||
default: {
|
||||
// Other auth data
|
||||
const authDataMatch = key.match(/^authData\.([a-zA-Z0-9_]+)\.id$/);
|
||||
@@ -923,11 +943,15 @@ const mongoObjectToParseObject = (className, mongoObject, schema) => {
|
||||
case '_expiresAt':
|
||||
restObject['expiresAt'] = Parse._encode(new Date(mongoObject[key]));
|
||||
break;
|
||||
case 'lastUsed':
|
||||
case '_last_used':
|
||||
restObject['lastUsed'] = Parse._encode(new Date(mongoObject[key])).iso;
|
||||
break;
|
||||
case 'timesUsed':
|
||||
case 'times_used':
|
||||
restObject['timesUsed'] = mongoObject[key];
|
||||
break;
|
||||
default:
|
||||
if (className === '_Audience' && (key === '_last_used' || key === 'times_used')) {
|
||||
// Ignore these parse.com legacy fields
|
||||
break;
|
||||
}
|
||||
// Check other auth data keys
|
||||
var authDataMatch = key.match(/^_auth_data_([a-zA-Z0-9_]+)$/);
|
||||
if (authDataMatch) {
|
||||
|
||||
@@ -54,6 +54,20 @@ export class PushController {
|
||||
}).then(() => {
|
||||
onPushStatusSaved(pushStatus.objectId);
|
||||
return badgeUpdate();
|
||||
}).then(() => {
|
||||
// Update audience lastUsed and timesUsed
|
||||
if (body.audience_id) {
|
||||
const audienceId = body.audience_id;
|
||||
|
||||
var updateAudience = {
|
||||
lastUsed: { __type: "Date", iso: new Date().toISOString() },
|
||||
timesUsed: { __op: "Increment", "amount": 1 }
|
||||
};
|
||||
const write = new RestWrite(config, master(config), '_Audience', {objectId: audienceId}, updateAudience);
|
||||
write.execute();
|
||||
}
|
||||
// Don't wait for the audience update promise to resolve.
|
||||
return Promise.resolve();
|
||||
}).then(() => {
|
||||
if (body.hasOwnProperty('push_time') && config.hasPushScheduledSupport) {
|
||||
return Promise.resolve();
|
||||
|
||||
@@ -113,12 +113,14 @@ const defaultColumns = Object.freeze({
|
||||
},
|
||||
_GlobalConfig: {
|
||||
"objectId": {type: 'String'},
|
||||
"params": {type: 'Object'}
|
||||
"params": {type: 'Object'}
|
||||
},
|
||||
_Audience: {
|
||||
"objectId": {type:'String'},
|
||||
"name": {type:'String'},
|
||||
"query": {type:'String'} //storing query as JSON string to prevent "Nested keys should not contain the '$' or '.' characters" error
|
||||
"objectId": {type:'String'},
|
||||
"name": {type:'String'},
|
||||
"query": {type:'String'}, //storing query as JSON string to prevent "Nested keys should not contain the '$' or '.' characters" error
|
||||
"lastUsed": {type:'Date'},
|
||||
"timesUsed": {type:'Number'}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user