* #6101 Let users define objectId * Add `allowCustomObjectId` to PS Option * Add checking in objectId creation * Add test * Update docs * Update definition * Change default to false * throw on empty, null, undefined * better tests * unused async * removed comment * retain comment * Linting fix according to contributing spec.
This commit is contained in:
@@ -44,6 +44,66 @@ describe('rest create', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should use objectId from client when allowCustomObjectId true', async () => {
|
||||
config.allowCustomObjectId = true;
|
||||
|
||||
// use time as unique custom id for test reusability
|
||||
const customId = `${Date.now()}`;
|
||||
const obj = {
|
||||
objectId: customId,
|
||||
};
|
||||
|
||||
const {
|
||||
status,
|
||||
response: { objectId },
|
||||
} = await rest.create(config, auth.nobody(config), 'MyClass', obj);
|
||||
|
||||
expect(status).toEqual(201);
|
||||
expect(objectId).toEqual(customId);
|
||||
});
|
||||
|
||||
it('should throw on invalid objectId when allowCustomObjectId true', () => {
|
||||
config.allowCustomObjectId = true;
|
||||
|
||||
const objIdNull = {
|
||||
objectId: null,
|
||||
};
|
||||
|
||||
const objIdUndef = {
|
||||
objectId: undefined,
|
||||
};
|
||||
|
||||
const objIdEmpty = {
|
||||
objectId: '',
|
||||
};
|
||||
|
||||
const err = 'objectId must not be empty, null or undefined';
|
||||
|
||||
expect(() =>
|
||||
rest.create(config, auth.nobody(config), 'MyClass', objIdEmpty)
|
||||
).toThrowError(err);
|
||||
|
||||
expect(() =>
|
||||
rest.create(config, auth.nobody(config), 'MyClass', objIdNull)
|
||||
).toThrowError(err);
|
||||
|
||||
expect(() =>
|
||||
rest.create(config, auth.nobody(config), 'MyClass', objIdUndef)
|
||||
).toThrowError(err);
|
||||
});
|
||||
|
||||
it('should generate objectId when not set by client with allowCustomObjectId true', async () => {
|
||||
config.allowCustomObjectId = true;
|
||||
|
||||
const {
|
||||
status,
|
||||
response: { objectId },
|
||||
} = await rest.create(config, auth.nobody(config), 'MyClass', {});
|
||||
|
||||
expect(status).toEqual(201);
|
||||
expect(objectId).toBeDefined();
|
||||
});
|
||||
|
||||
it('is backwards compatible when _id size changes', done => {
|
||||
rest
|
||||
.create(config, auth.nobody(config), 'Foo', { size: 10 })
|
||||
|
||||
@@ -17,6 +17,12 @@ module.exports.ParseServerOptions = {
|
||||
action: parsers.booleanParser,
|
||||
default: true,
|
||||
},
|
||||
allowCustomObjectId: {
|
||||
env: 'PARSE_SERVER_ALLOW_CUSTOM_OBJECT_ID',
|
||||
help: 'Enable (or disable) custom objectId, defaults to false',
|
||||
action: parsers.booleanParser,
|
||||
default: false,
|
||||
},
|
||||
allowHeaders: {
|
||||
env: 'PARSE_SERVER_ALLOW_HEADERS',
|
||||
help: 'Add headers to Access-Control-Allow-Headers',
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* @interface ParseServerOptions
|
||||
* @property {Any} accountLockout account lockout policy for failed login attempts
|
||||
* @property {Boolean} allowClientClassCreation Enable (or disable) client class creation, defaults to true
|
||||
* @property {Boolean} allowCustomObjectId Enable (or disable) custom objectId, defaults to false
|
||||
* @property {String[]} allowHeaders Add headers to Access-Control-Allow-Headers
|
||||
* @property {Adapter<AnalyticsAdapter>} analyticsAdapter Adapter module for the analytics
|
||||
* @property {String} appId Your Parse Application ID
|
||||
|
||||
@@ -102,6 +102,10 @@ export interface ParseServerOptions {
|
||||
:ENV: PARSE_SERVER_ALLOW_CLIENT_CLASS_CREATION
|
||||
:DEFAULT: true */
|
||||
allowClientClassCreation: ?boolean;
|
||||
/* Enable (or disable) custom objectId
|
||||
:ENV: PARSE_SERVER_ALLOW_CUSTOM_OBJECT_ID
|
||||
:DEFAULT: false */
|
||||
allowCustomObjectId: ?boolean;
|
||||
/* Configuration for your authentication providers, as stringified JSON. See http://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication
|
||||
:ENV: PARSE_SERVER_AUTH_PROVIDERS */
|
||||
auth: ?any;
|
||||
|
||||
@@ -46,17 +46,32 @@ function RestWrite(
|
||||
this.storage = {};
|
||||
this.runOptions = {};
|
||||
this.context = {};
|
||||
if (!query && data.objectId) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_KEY_NAME,
|
||||
'objectId is an invalid field name.'
|
||||
);
|
||||
}
|
||||
if (!query && data.id) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_KEY_NAME,
|
||||
'id is an invalid field name.'
|
||||
);
|
||||
|
||||
if (!query) {
|
||||
if (this.config.allowCustomObjectId) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(data, 'objectId') &&
|
||||
!data.objectId
|
||||
) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.MISSING_OBJECT_ID,
|
||||
'objectId must not be empty, null or undefined'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (data.objectId) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_KEY_NAME,
|
||||
'objectId is an invalid field name.'
|
||||
);
|
||||
}
|
||||
if (data.id) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_KEY_NAME,
|
||||
'id is an invalid field name.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When the operation is complete, this.response may have several
|
||||
|
||||
Reference in New Issue
Block a user