2016-02-29 19:45:12 -08:00
'use strict' ;
2016-02-05 14:56:11 -08:00
var Parse = require ( 'parse/node' ) . Parse ;
2016-02-03 11:55:44 -08:00
var request = require ( 'request' ) ;
var dd = require ( 'deep-diff' ) ;
2016-02-17 19:00:17 -08:00
var Config = require ( '../src/Config' ) ;
2017-05-14 10:50:53 -04:00
var config ;
2016-02-05 14:56:11 -08:00
2016-02-03 16:10:00 -08:00
var hasAllPODobject = ( ) => {
var obj = new Parse . Object ( 'HasAllPOD' ) ;
obj . set ( 'aNumber' , 5 ) ;
obj . set ( 'aString' , 'string' ) ;
obj . set ( 'aBool' , true ) ;
obj . set ( 'aDate' , new Date ( ) ) ;
obj . set ( 'aObject' , { k1 : 'value' , k2 : true , k3 : 5 } ) ;
obj . set ( 'aArray' , [ 'contents' , true , 5 ] ) ;
obj . set ( 'aGeoPoint' , new Parse . GeoPoint ( { latitude : 0 , longitude : 0 } ) ) ;
obj . set ( 'aFile' , new Parse . File ( 'f.txt' , { base64 : 'V29ya2luZyBhdCBQYXJzZSBpcyBncmVhdCE=' } ) ) ;
var objACL = new Parse . ACL ( ) ;
objACL . setPublicWriteAccess ( false ) ;
obj . setACL ( objACL ) ;
return obj ;
2016-02-08 20:20:08 -08:00
} ;
2016-02-03 16:10:00 -08:00
2016-12-07 15:17:05 -08:00
const defaultClassLevelPermissions = {
2016-03-10 23:01:45 -05:00
find : {
'*' : true
} ,
create : {
'*' : true
} ,
get : {
'*' : true
} ,
update : {
'*' : true
} ,
addField : {
'*' : true
} ,
delete : {
'*' : true
}
}
2016-02-05 20:38:58 -08:00
var plainOldDataSchema = {
2016-02-03 16:10:00 -08:00
className : 'HasAllPOD' ,
fields : {
//Default fields
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
//Custom fields
aNumber : { type : 'Number' } ,
aString : { type : 'String' } ,
aBool : { type : 'Boolean' } ,
aDate : { type : 'Date' } ,
aObject : { type : 'Object' } ,
aArray : { type : 'Array' } ,
aGeoPoint : { type : 'GeoPoint' } ,
aFile : { type : 'File' }
2016-03-10 23:01:45 -05:00
} ,
classLevelPermissions : defaultClassLevelPermissions
2016-02-03 16:10:00 -08:00
} ;
2016-02-05 20:38:58 -08:00
var pointersAndRelationsSchema = {
2016-02-03 16:10:00 -08:00
className : 'HasPointersAndRelations' ,
fields : {
//Default fields
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
//Custom fields
aPointer : {
type : 'Pointer' ,
targetClass : 'HasAllPOD' ,
} ,
aRelation : {
type : 'Relation' ,
targetClass : 'HasAllPOD' ,
} ,
} ,
2016-03-10 23:01:45 -05:00
classLevelPermissions : defaultClassLevelPermissions
2016-02-03 16:10:00 -08:00
}
2016-02-03 11:55:44 -08:00
2016-06-16 15:39:05 -07:00
const userSchema = {
"className" : "_User" ,
"fields" : {
"objectId" : { "type" : "String" } ,
"createdAt" : { "type" : "Date" } ,
"updatedAt" : { "type" : "Date" } ,
"ACL" : { "type" : "ACL" } ,
"username" : { "type" : "String" } ,
"password" : { "type" : "String" } ,
"email" : { "type" : "String" } ,
2016-09-09 14:41:03 -04:00
"emailVerified" : { "type" : "Boolean" } ,
"authData" : { "type" : "Object" }
2016-06-16 15:39:05 -07:00
} ,
"classLevelPermissions" : defaultClassLevelPermissions ,
}
2017-03-04 22:42:19 +02:00
const roleSchema = {
"className" : "_Role" ,
"fields" : {
"objectId" : { "type" : "String" } ,
"createdAt" : { "type" : "Date" } ,
"updatedAt" : { "type" : "Date" } ,
"ACL" : { "type" : "ACL" } ,
"name" : { "type" : "String" } ,
"users" : { "type" : "Relation" , "targetClass" : "_User" } ,
"roles" : { "type" : "Relation" , "targetClass" : "_Role" }
} ,
"classLevelPermissions" : defaultClassLevelPermissions ,
}
2016-02-05 14:56:11 -08:00
var noAuthHeaders = {
'X-Parse-Application-Id' : 'test' ,
} ;
var restKeyHeaders = {
'X-Parse-Application-Id' : 'test' ,
'X-Parse-REST-API-Key' : 'rest' ,
} ;
var masterKeyHeaders = {
'X-Parse-Application-Id' : 'test' ,
'X-Parse-Master-Key' : 'test' ,
} ;
2016-02-03 11:55:44 -08:00
describe ( 'schemas' , ( ) => {
2016-11-24 15:47:41 -05:00
beforeEach ( ( ) => {
2017-10-23 08:43:05 -04:00
config = Config . get ( 'test' ) ;
2017-05-14 10:50:53 -04:00
} ) ;
afterEach ( ( ) => {
2016-11-24 15:47:41 -05:00
config . database . schemaCache . clear ( ) ;
2016-07-23 06:23:59 +02:00
} ) ;
2016-02-03 11:55:44 -08:00
it ( 'requires the master key to get all schemas' , ( done ) => {
request . get ( {
url : 'http://localhost:8378/1/schemas' ,
json : true ,
2016-02-05 14:56:11 -08:00
headers : noAuthHeaders ,
2016-02-03 11:55:44 -08:00
} , ( error , response , body ) => {
2016-02-05 14:56:11 -08:00
//api.parse.com uses status code 401, but due to the lack of keys
//being necessary in parse-server, 403 makes more sense
expect ( response . statusCode ) . toEqual ( 403 ) ;
2016-02-03 11:55:44 -08:00
expect ( body . error ) . toEqual ( 'unauthorized' ) ;
done ( ) ;
} ) ;
} ) ;
2016-02-03 16:10:00 -08:00
it ( 'requires the master key to get one schema' , ( done ) => {
request . get ( {
url : 'http://localhost:8378/1/schemas/SomeSchema' ,
json : true ,
2016-02-05 20:38:58 -08:00
headers : restKeyHeaders ,
2016-02-03 16:10:00 -08:00
} , ( error , response , body ) => {
2016-03-01 15:17:10 -08:00
expect ( response . statusCode ) . toEqual ( 403 ) ;
expect ( body . error ) . toEqual ( 'unauthorized: master key is required' ) ;
2016-02-03 16:10:00 -08:00
done ( ) ;
} ) ;
} ) ;
2016-02-05 14:56:11 -08:00
it ( 'asks for the master key if you use the rest key' , ( done ) => {
request . get ( {
url : 'http://localhost:8378/1/schemas' ,
json : true ,
headers : restKeyHeaders ,
} , ( error , response , body ) => {
2016-03-01 15:17:10 -08:00
expect ( response . statusCode ) . toEqual ( 403 ) ;
expect ( body . error ) . toEqual ( 'unauthorized: master key is required' ) ;
2016-02-05 14:56:11 -08:00
done ( ) ;
} ) ;
} ) ;
2016-08-15 16:48:39 -04:00
it ( 'creates _User schema when server starts' , done => {
2016-02-03 11:55:44 -08:00
request . get ( {
url : 'http://localhost:8378/1/schemas' ,
json : true ,
2016-02-05 14:56:11 -08:00
headers : masterKeyHeaders ,
2016-02-03 11:55:44 -08:00
} , ( error , response , body ) => {
2017-03-04 22:42:19 +02:00
var expected = {
results : [ userSchema , roleSchema ]
} ;
expect ( dd ( body . results . sort ( ( s1 , s2 ) => s1 . className > s2 . className ) , expected . results . sort ( ( s1 , s2 ) => s1 . className > s2 . className ) ) ) . toEqual ( undefined ) ;
2016-02-03 11:55:44 -08:00
done ( ) ;
} ) ;
} ) ;
2016-08-18 18:05:26 -04:00
it ( 'responds with a list of schemas after creating objects' , done => {
2016-02-03 16:10:00 -08:00
var obj1 = hasAllPODobject ( ) ;
obj1 . save ( ) . then ( savedObj1 => {
var obj2 = new Parse . Object ( 'HasPointersAndRelations' ) ;
obj2 . set ( 'aPointer' , savedObj1 ) ;
var relation = obj2 . relation ( 'aRelation' ) ;
relation . add ( obj1 ) ;
return obj2 . save ( ) ;
} ) . then ( ( ) => {
request . get ( {
url : 'http://localhost:8378/1/schemas' ,
json : true ,
2016-02-05 14:56:11 -08:00
headers : masterKeyHeaders ,
2016-02-03 16:10:00 -08:00
} , ( error , response , body ) => {
var expected = {
2017-03-04 22:42:19 +02:00
results : [ userSchema , roleSchema , plainOldDataSchema , pointersAndRelationsSchema ]
2016-02-03 16:10:00 -08:00
} ;
2017-03-04 22:42:19 +02:00
expect ( dd ( body . results . sort ( ( s1 , s2 ) => s1 . className > s2 . className ) , expected . results . sort ( ( s1 , s2 ) => s1 . className > s2 . className ) ) ) . toEqual ( undefined ) ;
2016-02-03 16:10:00 -08:00
done ( ) ;
} )
} ) ;
} ) ;
2016-02-03 11:55:44 -08:00
2016-08-18 18:05:26 -04:00
it ( 'responds with a single schema' , done => {
2016-02-03 16:10:00 -08:00
var obj = hasAllPODobject ( ) ;
obj . save ( ) . then ( ( ) => {
request . get ( {
url : 'http://localhost:8378/1/schemas/HasAllPOD' ,
json : true ,
2016-02-05 20:38:58 -08:00
headers : masterKeyHeaders ,
2016-02-03 16:10:00 -08:00
} , ( error , response , body ) => {
2016-02-05 20:38:58 -08:00
expect ( body ) . toEqual ( plainOldDataSchema ) ;
2016-02-03 16:10:00 -08:00
done ( ) ;
2016-02-03 11:55:44 -08:00
} ) ;
2016-02-03 16:10:00 -08:00
} ) ;
} ) ;
2016-08-18 18:05:26 -04:00
it ( 'treats class names case sensitively' , done => {
2016-02-03 16:10:00 -08:00
var obj = hasAllPODobject ( ) ;
obj . save ( ) . then ( ( ) => {
request . get ( {
url : 'http://localhost:8378/1/schemas/HASALLPOD' ,
json : true ,
2016-02-05 20:38:58 -08:00
headers : masterKeyHeaders ,
2016-02-03 16:10:00 -08:00
} , ( error , response , body ) => {
expect ( response . statusCode ) . toEqual ( 400 ) ;
expect ( body ) . toEqual ( {
code : 103 ,
2016-03-02 21:33:33 -08:00
error : 'Class HASALLPOD does not exist.' ,
2016-02-03 16:10:00 -08:00
} ) ;
done ( ) ;
} ) ;
} ) ;
2016-02-03 11:55:44 -08:00
} ) ;
2016-02-05 14:56:11 -08:00
it ( 'requires the master key to create a schema' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas' ,
json : true ,
headers : noAuthHeaders ,
body : {
className : 'MyClass' ,
}
} , ( error , response , body ) => {
expect ( response . statusCode ) . toEqual ( 403 ) ;
expect ( body . error ) . toEqual ( 'unauthorized' ) ;
done ( ) ;
} ) ;
} ) ;
it ( 'asks for the master key if you use the rest key' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas' ,
json : true ,
headers : restKeyHeaders ,
body : {
className : 'MyClass' ,
} ,
} , ( error , response , body ) => {
2016-03-01 15:17:10 -08:00
expect ( response . statusCode ) . toEqual ( 403 ) ;
expect ( body . error ) . toEqual ( 'unauthorized: master key is required' ) ;
2016-02-05 14:56:11 -08:00
done ( ) ;
} ) ;
} ) ;
it ( 'sends an error if you use mismatching class names' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/A' ,
headers : masterKeyHeaders ,
json : true ,
body : {
className : 'B' ,
}
} , ( error , response , body ) => {
expect ( response . statusCode ) . toEqual ( 400 ) ;
expect ( body ) . toEqual ( {
code : Parse . Error . INVALID _CLASS _NAME ,
2016-03-02 21:38:06 -08:00
error : 'Class name mismatch between B and A.' ,
2016-02-05 14:56:11 -08:00
} ) ;
done ( ) ;
} ) ;
} ) ;
it ( 'sends an error if you use no class name' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas' ,
headers : masterKeyHeaders ,
json : true ,
body : { } ,
} , ( error , response , body ) => {
expect ( response . statusCode ) . toEqual ( 400 ) ;
expect ( body ) . toEqual ( {
code : 135 ,
2016-03-02 21:38:06 -08:00
error : 'POST /schemas needs a class name.' ,
2016-02-05 14:56:11 -08:00
} ) ;
done ( ) ;
} )
} ) ;
it ( 'sends an error if you try to create the same class twice' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas' ,
headers : masterKeyHeaders ,
json : true ,
body : {
className : 'A' ,
} ,
2016-11-24 15:47:41 -05:00
} , ( error ) => {
2016-02-05 14:56:11 -08:00
expect ( error ) . toEqual ( null ) ;
request . post ( {
url : 'http://localhost:8378/1/schemas' ,
headers : masterKeyHeaders ,
json : true ,
body : {
className : 'A' ,
}
} , ( error , response , body ) => {
expect ( response . statusCode ) . toEqual ( 400 ) ;
expect ( body ) . toEqual ( {
code : Parse . Error . INVALID _CLASS _NAME ,
2016-03-02 21:38:06 -08:00
error : 'Class A already exists.'
2016-02-05 14:56:11 -08:00
} ) ;
done ( ) ;
} ) ;
} ) ;
} ) ;
2016-08-15 16:48:39 -04:00
it ( 'responds with all fields when you create a class' , done => {
2016-02-05 14:56:11 -08:00
request . post ( {
url : 'http://localhost:8378/1/schemas' ,
headers : masterKeyHeaders ,
json : true ,
2016-02-05 20:38:58 -08:00
body : {
className : "NewClass" ,
fields : {
foo : { type : 'Number' } ,
ptr : { type : 'Pointer' , targetClass : 'SomeClass' }
}
}
} , ( error , response , body ) => {
expect ( body ) . toEqual ( {
className : 'NewClass' ,
fields : {
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
foo : { type : 'Number' } ,
ptr : { type : 'Pointer' , targetClass : 'SomeClass' } ,
2016-03-10 23:01:45 -05:00
} ,
classLevelPermissions : defaultClassLevelPermissions
2016-02-05 20:38:58 -08:00
} ) ;
done ( ) ;
} ) ;
} ) ;
2016-08-15 16:48:39 -04:00
it ( 'responds with all fields when getting incomplete schema' , done => {
2016-06-12 16:35:13 -07:00
config . database . loadSchema ( )
2017-06-20 09:15:26 -07:00
. then ( schemaController => schemaController . addClassIfNotExists ( '_Installation' , { } , defaultClassLevelPermissions ) )
. then ( ( ) => {
request . get ( {
url : 'http://localhost:8378/1/schemas/_Installation' ,
headers : masterKeyHeaders ,
json : true
} , ( error , response , body ) => {
expect ( dd ( body , {
className : '_Installation' ,
fields : {
objectId : { type : 'String' } ,
updatedAt : { type : 'Date' } ,
createdAt : { type : 'Date' } ,
installationId : { type : 'String' } ,
deviceToken : { type : 'String' } ,
channels : { type : 'Array' } ,
deviceType : { type : 'String' } ,
pushType : { type : 'String' } ,
GCMSenderId : { type : 'String' } ,
timeZone : { type : 'String' } ,
badge : { type : 'Number' } ,
appIdentifier : { type : 'String' } ,
localeIdentifier : { type : 'String' } ,
appVersion : { type : 'String' } ,
appName : { type : 'String' } ,
parseVersion : { type : 'String' } ,
ACL : { type : 'ACL' }
} ,
classLevelPermissions : defaultClassLevelPermissions
} ) ) . toBeUndefined ( ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
fail ( JSON . stringify ( error ) )
2016-04-07 22:13:07 -04:00
done ( ) ;
} ) ;
} ) ;
2016-08-15 16:48:39 -04:00
it ( 'lets you specify class name in both places' , done => {
2016-02-05 20:38:58 -08:00
request . post ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
2016-02-05 14:56:11 -08:00
body : {
className : "NewClass" ,
}
} , ( error , response , body ) => {
expect ( body ) . toEqual ( {
className : 'NewClass' ,
fields : {
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
2016-03-10 23:01:45 -05:00
} ,
classLevelPermissions : defaultClassLevelPermissions
2016-02-05 14:56:11 -08:00
} ) ;
done ( ) ;
} ) ;
} ) ;
2016-02-09 11:26:46 -08:00
it ( 'requires the master key to modify schemas' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : { } ,
2016-11-24 15:47:41 -05:00
} , ( ) => {
2016-02-09 11:26:46 -08:00
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : noAuthHeaders ,
json : true ,
body : { } ,
} , ( error , response , body ) => {
expect ( response . statusCode ) . toEqual ( 403 ) ;
expect ( body . error ) . toEqual ( 'unauthorized' ) ;
done ( ) ;
} ) ;
} ) ;
} ) ;
2016-02-16 12:30:30 -08:00
it ( 'rejects class name mis-matches in put' , done => {
2016-02-09 11:26:46 -08:00
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : { className : 'WrongClassName' }
} , ( error , response , body ) => {
expect ( response . statusCode ) . toEqual ( 400 ) ;
expect ( body . code ) . toEqual ( Parse . Error . INVALID _CLASS _NAME ) ;
2016-03-02 21:38:06 -08:00
expect ( body . error ) . toEqual ( 'Class name mismatch between WrongClassName and NewClass.' ) ;
2016-02-16 12:30:30 -08:00
done ( ) ;
2016-02-09 11:26:46 -08:00
} ) ;
} ) ;
it ( 'refuses to add fields to non-existent classes' , done => {
request . put ( {
url : 'http://localhost:8378/1/schemas/NoClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
2016-11-24 15:47:41 -05:00
newField : { type : 'String' }
2016-02-09 11:26:46 -08:00
}
}
} , ( error , response , body ) => {
expect ( response . statusCode ) . toEqual ( 400 ) ;
expect ( body . code ) . toEqual ( Parse . Error . INVALID _CLASS _NAME ) ;
2016-02-29 17:41:09 -08:00
expect ( body . error ) . toEqual ( 'Class NoClass does not exist.' ) ;
2016-02-09 11:26:46 -08:00
done ( ) ;
} ) ;
} ) ;
2016-08-18 18:05:26 -04:00
it ( 'refuses to put to existing fields, even if it would not be a change' , done => {
2016-02-16 12:30:30 -08:00
var obj = hasAllPODobject ( ) ;
obj . save ( )
2017-06-20 09:15:26 -07:00
. then ( ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/HasAllPOD' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
aString : { type : 'String' }
}
2016-02-16 12:30:30 -08:00
}
2017-06-20 09:15:26 -07:00
} , ( error , response , body ) => {
expect ( response . statusCode ) . toEqual ( 400 ) ;
expect ( body . code ) . toEqual ( 255 ) ;
expect ( body . error ) . toEqual ( 'Field aString exists, cannot update.' ) ;
done ( ) ;
} ) ;
} )
2016-02-16 12:30:30 -08:00
} ) ;
2016-08-18 18:05:26 -04:00
it ( 'refuses to delete non-existent fields' , done => {
2016-02-16 12:30:30 -08:00
var obj = hasAllPODobject ( ) ;
obj . save ( )
2017-06-20 09:15:26 -07:00
. then ( ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/HasAllPOD' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
nonExistentKey : { _ _op : "Delete" } ,
}
2016-02-16 12:30:30 -08:00
}
2017-06-20 09:15:26 -07:00
} , ( error , response , body ) => {
expect ( response . statusCode ) . toEqual ( 400 ) ;
expect ( body . code ) . toEqual ( 255 ) ;
expect ( body . error ) . toEqual ( 'Field nonExistentKey does not exist, cannot delete.' ) ;
done ( ) ;
} ) ;
2016-02-16 12:30:30 -08:00
} ) ;
} ) ;
2016-08-18 18:05:26 -04:00
it ( 'refuses to add a geopoint to a class that already has one' , done => {
2016-02-16 12:30:30 -08:00
var obj = hasAllPODobject ( ) ;
obj . save ( )
2017-06-20 09:15:26 -07:00
. then ( ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/HasAllPOD' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
newGeo : { type : 'GeoPoint' }
}
2016-02-16 12:30:30 -08:00
}
2017-06-20 09:15:26 -07:00
} , ( error , response , body ) => {
expect ( response . statusCode ) . toEqual ( 400 ) ;
expect ( body . code ) . toEqual ( Parse . Error . INCORRECT _TYPE ) ;
expect ( body . error ) . toEqual ( 'currently, only one GeoPoint field may exist in an object. Adding newGeo when aGeoPoint already exists.' ) ;
done ( ) ;
} ) ;
2016-02-16 12:30:30 -08:00
} ) ;
} ) ;
it ( 'refuses to add two geopoints' , done => {
var obj = new Parse . Object ( 'NewClass' ) ;
obj . set ( 'aString' , 'aString' ) ;
obj . save ( )
2017-06-20 09:15:26 -07:00
. then ( ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
newGeo1 : { type : 'GeoPoint' } ,
newGeo2 : { type : 'GeoPoint' } ,
}
2016-02-16 12:30:30 -08:00
}
2017-06-20 09:15:26 -07:00
} , ( error , response , body ) => {
expect ( response . statusCode ) . toEqual ( 400 ) ;
expect ( body . code ) . toEqual ( Parse . Error . INCORRECT _TYPE ) ;
expect ( body . error ) . toEqual ( 'currently, only one GeoPoint field may exist in an object. Adding newGeo2 when newGeo1 already exists.' ) ;
done ( ) ;
} ) ;
2016-02-16 12:30:30 -08:00
} ) ;
} ) ;
2016-08-18 18:05:26 -04:00
it ( 'allows you to delete and add a geopoint in the same request' , done => {
2016-02-16 12:30:30 -08:00
var obj = new Parse . Object ( 'NewClass' ) ;
obj . set ( 'geo1' , new Parse . GeoPoint ( { latitude : 0 , longitude : 0 } ) ) ;
obj . save ( )
2017-06-20 09:15:26 -07:00
. then ( ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
geo2 : { type : 'GeoPoint' } ,
geo1 : { _ _op : 'Delete' }
}
2016-02-16 12:30:30 -08:00
}
2017-06-20 09:15:26 -07:00
} , ( error , response , body ) => {
expect ( dd ( body , {
"className" : "NewClass" ,
"fields" : {
"ACL" : { "type" : "ACL" } ,
"createdAt" : { "type" : "Date" } ,
"objectId" : { "type" : "String" } ,
"updatedAt" : { "type" : "Date" } ,
"geo2" : { "type" : "GeoPoint" } ,
} ,
classLevelPermissions : defaultClassLevelPermissions
} ) ) . toEqual ( undefined ) ;
done ( ) ;
} ) ;
} )
2016-02-16 12:30:30 -08:00
} ) ;
2016-08-18 18:05:26 -04:00
it ( 'put with no modifications returns all fields' , done => {
2016-02-09 11:26:46 -08:00
var obj = hasAllPODobject ( ) ;
obj . save ( )
2017-06-20 09:15:26 -07:00
. then ( ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/HasAllPOD' ,
headers : masterKeyHeaders ,
json : true ,
body : { } ,
} , ( error , response , body ) => {
expect ( body ) . toEqual ( plainOldDataSchema ) ;
done ( ) ;
} ) ;
} )
2016-02-09 11:26:46 -08:00
} ) ;
2016-08-15 16:48:39 -04:00
it ( 'lets you add fields' , done => {
2016-02-09 11:26:46 -08:00
request . post ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : { } ,
2016-11-24 15:47:41 -05:00
} , ( ) => {
2016-02-09 11:26:46 -08:00
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
newField : { type : 'String' }
}
}
} , ( error , response , body ) => {
2016-02-16 12:30:30 -08:00
expect ( dd ( body , {
className : 'NewClass' ,
fields : {
"ACL" : { "type" : "ACL" } ,
"createdAt" : { "type" : "Date" } ,
"objectId" : { "type" : "String" } ,
"updatedAt" : { "type" : "Date" } ,
"newField" : { "type" : "String" } ,
} ,
2016-03-10 23:01:45 -05:00
classLevelPermissions : defaultClassLevelPermissions
2016-02-16 12:30:30 -08:00
} ) ) . toEqual ( undefined ) ;
2016-02-09 11:26:46 -08:00
request . get ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
} , ( error , response , body ) => {
2016-02-16 12:30:30 -08:00
expect ( body ) . toEqual ( {
className : 'NewClass' ,
fields : {
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
newField : { type : 'String' } ,
2016-03-10 23:01:45 -05:00
} ,
classLevelPermissions : defaultClassLevelPermissions
2016-02-16 12:30:30 -08:00
} ) ;
2016-02-09 11:26:46 -08:00
done ( ) ;
} ) ;
} ) ;
} )
} ) ;
2016-02-16 12:30:30 -08:00
2016-08-15 16:48:39 -04:00
it ( 'lets you add fields to system schema' , done => {
2016-03-04 20:44:21 +08:00
request . post ( {
url : 'http://localhost:8378/1/schemas/_User' ,
headers : masterKeyHeaders ,
json : true
2016-11-24 15:47:41 -05:00
} , ( ) => {
2016-03-04 20:44:21 +08:00
request . put ( {
url : 'http://localhost:8378/1/schemas/_User' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
newField : { type : 'String' }
}
}
} , ( error , response , body ) => {
2016-06-16 15:39:05 -07:00
expect ( dd ( body , {
2016-03-04 20:44:21 +08:00
className : '_User' ,
fields : {
objectId : { type : 'String' } ,
updatedAt : { type : 'Date' } ,
createdAt : { type : 'Date' } ,
username : { type : 'String' } ,
password : { type : 'String' } ,
email : { type : 'String' } ,
emailVerified : { type : 'Boolean' } ,
2016-09-09 14:41:03 -04:00
authData : { type : 'Object' } ,
2016-03-04 20:44:21 +08:00
newField : { type : 'String' } ,
ACL : { type : 'ACL' }
2016-03-10 23:01:45 -05:00
} ,
classLevelPermissions : defaultClassLevelPermissions
2016-06-16 15:39:05 -07:00
} ) ) . toBeUndefined ( ) ;
2016-03-04 20:44:21 +08:00
request . get ( {
url : 'http://localhost:8378/1/schemas/_User' ,
headers : masterKeyHeaders ,
json : true
} , ( error , response , body ) => {
2016-06-16 15:39:05 -07:00
expect ( dd ( body , {
2016-03-04 20:44:21 +08:00
className : '_User' ,
fields : {
objectId : { type : 'String' } ,
updatedAt : { type : 'Date' } ,
createdAt : { type : 'Date' } ,
username : { type : 'String' } ,
password : { type : 'String' } ,
email : { type : 'String' } ,
emailVerified : { type : 'Boolean' } ,
2016-09-09 14:41:03 -04:00
authData : { type : 'Object' } ,
2016-03-04 20:44:21 +08:00
newField : { type : 'String' } ,
ACL : { type : 'ACL' }
2016-03-10 23:01:45 -05:00
} ,
classLevelPermissions : defaultClassLevelPermissions
2016-06-16 15:39:05 -07:00
} ) ) . toBeUndefined ( ) ;
2016-03-04 20:44:21 +08:00
done ( ) ;
} ) ;
} ) ;
} )
} ) ;
2017-04-23 18:22:55 -03:00
it ( 'lets you delete multiple fields and check schema' , done => {
var simpleOneObject = ( ) => {
var obj = new Parse . Object ( 'SimpleOne' ) ;
obj . set ( 'aNumber' , 5 ) ;
obj . set ( 'aString' , 'string' ) ;
obj . set ( 'aBool' , true ) ;
return obj ;
} ;
simpleOneObject ( ) . save ( )
. then ( ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/SimpleOne' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
aString : { _ _op : 'Delete' } ,
aNumber : { _ _op : 'Delete' } ,
}
}
} , ( error , response , body ) => {
expect ( body ) . toEqual ( {
className : 'SimpleOne' ,
fields : {
//Default fields
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
//Custom fields
aBool : { type : 'Boolean' } ,
} ,
classLevelPermissions : defaultClassLevelPermissions
} ) ;
done ( ) ;
} ) ;
} ) ;
} ) ;
2017-11-25 13:55:34 -06:00
it ( 'lets you delete multiple fields and add fields' , done => {
2016-02-16 12:30:30 -08:00
var obj1 = hasAllPODobject ( ) ;
obj1 . save ( )
2017-06-20 09:15:26 -07:00
. then ( ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/HasAllPOD' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
aString : { _ _op : 'Delete' } ,
aNumber : { _ _op : 'Delete' } ,
aNewString : { type : 'String' } ,
aNewNumber : { type : 'Number' } ,
aNewRelation : { type : 'Relation' , targetClass : 'HasAllPOD' } ,
aNewPointer : { type : 'Pointer' , targetClass : 'HasAllPOD' } ,
}
2016-02-16 12:30:30 -08:00
}
2017-06-20 09:15:26 -07:00
} , ( error , response , body ) => {
expect ( body ) . toEqual ( {
className : 'HasAllPOD' ,
fields : {
2016-02-16 12:30:30 -08:00
//Default fields
2017-06-20 09:15:26 -07:00
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
//Custom fields
aBool : { type : 'Boolean' } ,
aDate : { type : 'Date' } ,
aObject : { type : 'Object' } ,
aArray : { type : 'Array' } ,
aGeoPoint : { type : 'GeoPoint' } ,
aFile : { type : 'File' } ,
aNewNumber : { type : 'Number' } ,
aNewString : { type : 'String' } ,
aNewPointer : { type : 'Pointer' , targetClass : 'HasAllPOD' } ,
aNewRelation : { type : 'Relation' , targetClass : 'HasAllPOD' } ,
} ,
classLevelPermissions : defaultClassLevelPermissions
} ) ;
var obj2 = new Parse . Object ( 'HasAllPOD' ) ;
obj2 . set ( 'aNewPointer' , obj1 ) ;
var relation = obj2 . relation ( 'aNewRelation' ) ;
relation . add ( obj1 ) ;
obj2 . save ( ) . then ( done ) ; //Just need to make sure saving works on the new object.
2016-02-16 12:30:30 -08:00
} ) ;
} ) ;
} ) ;
2016-08-18 18:05:26 -04:00
it ( 'will not delete any fields if the additions are invalid' , done => {
2016-02-16 12:30:30 -08:00
var obj = hasAllPODobject ( ) ;
obj . save ( )
2017-06-20 09:15:26 -07:00
. then ( ( ) => {
request . put ( {
2016-02-16 12:30:30 -08:00
url : 'http://localhost:8378/1/schemas/HasAllPOD' ,
headers : masterKeyHeaders ,
json : true ,
2017-06-20 09:15:26 -07:00
body : {
fields : {
fakeNewField : { type : 'fake type' } ,
aString : { _ _op : 'Delete' }
}
}
} , ( error , response , body ) => {
expect ( body . code ) . toEqual ( Parse . Error . INCORRECT _TYPE ) ;
expect ( body . error ) . toEqual ( 'invalid field type: fake type' ) ;
request . get ( {
url : 'http://localhost:8378/1/schemas/HasAllPOD' ,
headers : masterKeyHeaders ,
json : true ,
} , ( error , response ) => {
expect ( response . body ) . toEqual ( plainOldDataSchema ) ;
done ( ) ;
} ) ;
2016-02-16 12:30:30 -08:00
} ) ;
} ) ;
} ) ;
2016-02-17 19:00:17 -08:00
it ( 'requires the master key to delete schemas' , done => {
request . del ( {
url : 'http://localhost:8378/1/schemas/DoesntMatter' ,
headers : noAuthHeaders ,
json : true ,
} , ( error , response , body ) => {
expect ( response . statusCode ) . toEqual ( 403 ) ;
expect ( body . error ) . toEqual ( 'unauthorized' ) ;
done ( ) ;
} ) ;
} ) ;
2016-08-18 18:05:26 -04:00
it ( 'refuses to delete non-empty collection' , done => {
2016-02-17 19:00:17 -08:00
var obj = hasAllPODobject ( ) ;
obj . save ( )
2017-06-20 09:15:26 -07:00
. then ( ( ) => {
request . del ( {
url : 'http://localhost:8378/1/schemas/HasAllPOD' ,
headers : masterKeyHeaders ,
json : true ,
} , ( error , response , body ) => {
expect ( response . statusCode ) . toEqual ( 400 ) ;
expect ( body . code ) . toEqual ( 255 ) ;
expect ( body . error ) . toMatch ( /HasAllPOD/ ) ;
expect ( body . error ) . toMatch ( /contains 1/ ) ;
done ( ) ;
} ) ;
2016-02-17 19:00:17 -08:00
} ) ;
} ) ;
it ( 'fails when deleting collections with invalid class names' , done => {
request . del ( {
url : 'http://localhost:8378/1/schemas/_GlobalConfig' ,
headers : masterKeyHeaders ,
json : true ,
} , ( error , response , body ) => {
expect ( response . statusCode ) . toEqual ( 400 ) ;
expect ( body . code ) . toEqual ( Parse . Error . INVALID _CLASS _NAME ) ;
expect ( body . error ) . toEqual ( 'Invalid classname: _GlobalConfig, classnames can only have alphanumeric characters and _, and must start with an alpha character ' ) ;
done ( ) ;
} )
} ) ;
2016-08-18 18:05:26 -04:00
it ( 'does not fail when deleting nonexistant collections' , done => {
2016-02-17 19:00:17 -08:00
request . del ( {
url : 'http://localhost:8378/1/schemas/Missing' ,
headers : masterKeyHeaders ,
json : true ,
} , ( error , response , body ) => {
expect ( response . statusCode ) . toEqual ( 200 ) ;
expect ( body ) . toEqual ( { } ) ;
done ( ) ;
} ) ;
} ) ;
2016-08-18 18:05:26 -04:00
it ( 'deletes collections including join tables' , done => {
2016-02-17 19:00:17 -08:00
var obj = new Parse . Object ( 'MyClass' ) ;
obj . set ( 'data' , 'data' ) ;
obj . save ( )
2017-06-20 09:15:26 -07:00
. then ( ( ) => {
var obj2 = new Parse . Object ( 'MyOtherClass' ) ;
var relation = obj2 . relation ( 'aRelation' ) ;
relation . add ( obj ) ;
return obj2 . save ( ) ;
} )
. then ( obj2 => obj2 . destroy ( ) )
. then ( ( ) => {
request . del ( {
url : 'http://localhost:8378/1/schemas/MyOtherClass' ,
headers : masterKeyHeaders ,
json : true ,
} , ( error , response ) => {
expect ( response . statusCode ) . toEqual ( 200 ) ;
expect ( response . body ) . toEqual ( { } ) ;
config . database . collectionExists ( '_Join:aRelation:MyOtherClass' ) . then ( exists => {
if ( exists ) {
fail ( 'Relation collection should be deleted.' ) ;
done ( ) ;
}
return config . database . collectionExists ( 'MyOtherClass' ) ;
} ) . then ( exists => {
if ( exists ) {
fail ( 'Class collection should be deleted.' ) ;
done ( ) ;
}
} ) . then ( ( ) => {
request . get ( {
url : 'http://localhost:8378/1/schemas/MyOtherClass' ,
headers : masterKeyHeaders ,
json : true ,
} , ( error , response , body ) => {
2016-02-29 19:45:12 -08:00
//Expect _SCHEMA entry to be gone.
2017-06-20 09:15:26 -07:00
expect ( response . statusCode ) . toEqual ( 400 ) ;
expect ( body . code ) . toEqual ( Parse . Error . INVALID _CLASS _NAME ) ;
expect ( body . error ) . toEqual ( 'Class MyOtherClass does not exist.' ) ;
done ( ) ;
} ) ;
2016-02-17 19:00:17 -08:00
} ) ;
} ) ;
2017-06-20 09:15:26 -07:00
} ) . then ( ( ) => {
} , error => {
fail ( error ) ;
done ( ) ;
2016-02-17 19:00:17 -08:00
} ) ;
} ) ;
2016-03-03 18:44:30 +08:00
2016-08-18 18:05:26 -04:00
it ( 'deletes schema when actual collection does not exist' , done => {
2016-03-03 18:44:30 +08:00
request . post ( {
url : 'http://localhost:8378/1/schemas/NewClassForDelete' ,
headers : masterKeyHeaders ,
json : true ,
body : {
className : 'NewClassForDelete'
}
2016-11-24 15:47:41 -05:00
} , ( error , response ) => {
2016-03-03 18:44:30 +08:00
expect ( error ) . toEqual ( null ) ;
expect ( response . body . className ) . toEqual ( 'NewClassForDelete' ) ;
request . del ( {
url : 'http://localhost:8378/1/schemas/NewClassForDelete' ,
headers : masterKeyHeaders ,
json : true ,
2016-11-24 15:47:41 -05:00
} , ( error , response ) => {
2016-03-03 18:44:30 +08:00
expect ( response . statusCode ) . toEqual ( 200 ) ;
expect ( response . body ) . toEqual ( { } ) ;
config . database . loadSchema ( ) . then ( schema => {
schema . hasClass ( 'NewClassForDelete' ) . then ( exist => {
expect ( exist ) . toEqual ( false ) ;
done ( ) ;
} ) ;
} )
} ) ;
} ) ;
} ) ;
2016-08-18 18:05:26 -04:00
it ( 'deletes schema when actual collection exists' , done => {
2016-03-03 18:44:30 +08:00
request . post ( {
url : 'http://localhost:8378/1/schemas/NewClassForDelete' ,
headers : masterKeyHeaders ,
json : true ,
body : {
className : 'NewClassForDelete'
}
2016-11-24 15:47:41 -05:00
} , ( error , response ) => {
2016-03-03 18:44:30 +08:00
expect ( error ) . toEqual ( null ) ;
expect ( response . body . className ) . toEqual ( 'NewClassForDelete' ) ;
request . post ( {
url : 'http://localhost:8378/1/classes/NewClassForDelete' ,
headers : restKeyHeaders ,
json : true
2016-11-24 15:47:41 -05:00
} , ( error , response ) => {
2016-03-03 18:44:30 +08:00
expect ( error ) . toEqual ( null ) ;
expect ( typeof response . body . objectId ) . toEqual ( 'string' ) ;
request . del ( {
url : 'http://localhost:8378/1/classes/NewClassForDelete/' + response . body . objectId ,
headers : restKeyHeaders ,
json : true ,
2016-11-24 15:47:41 -05:00
} , ( error ) => {
2016-03-03 18:44:30 +08:00
expect ( error ) . toEqual ( null ) ;
request . del ( {
url : 'http://localhost:8378/1/schemas/NewClassForDelete' ,
headers : masterKeyHeaders ,
json : true ,
2016-11-24 15:47:41 -05:00
} , ( error , response ) => {
2016-03-03 18:44:30 +08:00
expect ( response . statusCode ) . toEqual ( 200 ) ;
expect ( response . body ) . toEqual ( { } ) ;
config . database . loadSchema ( ) . then ( schema => {
schema . hasClass ( 'NewClassForDelete' ) . then ( exist => {
expect ( exist ) . toEqual ( false ) ;
done ( ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
2016-03-07 14:49:09 -05:00
2016-08-15 16:48:39 -04:00
it ( 'should set/get schema permissions' , done => {
2016-03-07 21:38:20 -05:00
request . post ( {
url : 'http://localhost:8378/1/schemas/AClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
classLevelPermissions : {
2016-03-07 14:49:09 -05:00
find : {
'*' : true
} ,
create : {
'role:admin' : true
}
}
2016-03-07 21:38:20 -05:00
}
2016-11-24 15:47:41 -05:00
} , ( error ) => {
2016-03-07 21:38:20 -05:00
expect ( error ) . toEqual ( null ) ;
request . get ( {
url : 'http://localhost:8378/1/schemas/AClass' ,
headers : masterKeyHeaders ,
json : true ,
2016-11-24 15:47:41 -05:00
} , ( error , response ) => {
2016-03-07 21:38:20 -05:00
expect ( response . statusCode ) . toEqual ( 200 ) ;
expect ( response . body . classLevelPermissions ) . toEqual ( {
find : {
'*' : true
} ,
create : {
'role:admin' : true
2016-03-10 23:01:45 -05:00
} ,
2016-06-06 12:31:50 -04:00
get : { } ,
update : { } ,
delete : { } ,
addField : { }
2016-03-07 14:49:09 -05:00
} ) ;
2016-03-07 21:38:20 -05:00
done ( ) ;
2016-03-07 14:49:09 -05:00
} ) ;
} ) ;
} ) ;
it ( 'should fail setting schema permissions with invalid key' , done => {
2016-12-07 15:17:05 -08:00
const object = new Parse . Object ( 'AClass' ) ;
2016-03-07 14:49:09 -05:00
object . save ( ) . then ( ( ) => {
request . put ( {
2016-03-07 21:38:20 -05:00
url : 'http://localhost:8378/1/schemas/AClass' ,
2016-03-07 14:49:09 -05:00
headers : masterKeyHeaders ,
json : true ,
body : {
2016-03-07 21:38:20 -05:00
classLevelPermissions : {
find : {
'*' : true
} ,
create : {
'role:admin' : true
} ,
dummy : {
'some' : true
}
2016-03-07 14:49:09 -05:00
}
}
} , ( error , response , body ) => {
expect ( error ) . toEqual ( null ) ;
expect ( body . code ) . toEqual ( 107 ) ;
expect ( body . error ) . toEqual ( 'dummy is not a valid operation for class level permissions' ) ;
done ( ) ;
} ) ;
} ) ;
} ) ;
2016-03-30 20:27:12 -04:00
2016-03-07 23:07:24 -05:00
it ( 'should not be able to add a field' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/AClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
classLevelPermissions : {
2016-06-06 12:31:50 -04:00
create : {
'*' : true
} ,
2016-03-07 23:07:24 -05:00
find : {
'*' : true
} ,
addField : {
'role:admin' : true
}
}
}
2016-11-24 15:47:41 -05:00
} , ( error ) => {
2016-03-07 23:07:24 -05:00
expect ( error ) . toEqual ( null ) ;
2016-12-07 15:17:05 -08:00
const object = new Parse . Object ( 'AClass' ) ;
2016-03-07 23:07:24 -05:00
object . set ( 'hello' , 'world' ) ;
2016-11-24 15:47:41 -05:00
return object . save ( ) . then ( ( ) => {
2016-03-07 23:07:24 -05:00
fail ( 'should not be able to add a field' ) ;
done ( ) ;
} , ( err ) => {
2016-07-08 03:30:29 +12:00
expect ( err . message ) . toEqual ( 'Permission denied for action addField on class AClass.' ) ;
2016-03-07 23:07:24 -05:00
done ( ) ;
} )
} )
} ) ;
2016-03-30 20:27:12 -04:00
2016-06-06 12:31:50 -04:00
it ( 'should be able to add a field' , done => {
2016-03-07 23:07:24 -05:00
request . post ( {
url : 'http://localhost:8378/1/schemas/AClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
classLevelPermissions : {
2016-06-06 12:31:50 -04:00
create : {
2016-03-07 23:07:24 -05:00
'*' : true
} ,
addField : {
'*' : true
}
}
}
2016-11-24 15:47:41 -05:00
} , ( error ) => {
2016-03-07 23:07:24 -05:00
expect ( error ) . toEqual ( null ) ;
2016-12-07 15:17:05 -08:00
const object = new Parse . Object ( 'AClass' ) ;
2016-03-07 23:07:24 -05:00
object . set ( 'hello' , 'world' ) ;
2016-11-24 15:47:41 -05:00
return object . save ( ) . then ( ( ) => {
2016-03-07 23:07:24 -05:00
done ( ) ;
2016-11-24 15:47:41 -05:00
} , ( ) => {
2016-03-07 23:07:24 -05:00
fail ( 'should be able to add a field' ) ;
done ( ) ;
} )
} )
} ) ;
2016-03-30 20:27:12 -04:00
2016-03-09 19:58:50 -05:00
it ( 'should throw with invalid userId (>10 chars)' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/AClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
classLevelPermissions : {
find : {
'1234567890A' : true
} ,
}
}
} , ( error , response , body ) => {
2016-11-24 15:47:41 -05:00
expect ( body . error ) . toEqual ( "'1234567890A' is not a valid key for class level permissions" ) ;
2016-03-09 19:58:50 -05:00
done ( ) ;
} )
} ) ;
2016-03-30 20:27:12 -04:00
2016-03-09 19:58:50 -05:00
it ( 'should throw with invalid userId (<10 chars)' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/AClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
classLevelPermissions : {
find : {
'a12345678' : true
} ,
}
}
} , ( error , response , body ) => {
expect ( body . error ) . toEqual ( "'a12345678' is not a valid key for class level permissions" ) ;
done ( ) ;
} )
} ) ;
2016-03-30 20:27:12 -04:00
2016-03-09 19:58:50 -05:00
it ( 'should throw with invalid userId (invalid char)' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/AClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
classLevelPermissions : {
find : {
'12345_6789' : true
} ,
}
}
} , ( error , response , body ) => {
expect ( body . error ) . toEqual ( "'12345_6789' is not a valid key for class level permissions" ) ;
done ( ) ;
} )
} ) ;
2016-03-30 20:27:12 -04:00
2016-03-09 19:58:50 -05:00
it ( 'should throw with invalid * (spaces)' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/AClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
classLevelPermissions : {
find : {
' *' : true
} ,
}
}
} , ( error , response , body ) => {
expect ( body . error ) . toEqual ( "' *' is not a valid key for class level permissions" ) ;
done ( ) ;
} )
} ) ;
2016-03-30 20:27:12 -04:00
2016-03-09 19:58:50 -05:00
it ( 'should throw with invalid * (spaces)' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/AClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
classLevelPermissions : {
find : {
'* ' : true
} ,
}
}
} , ( error , response , body ) => {
expect ( body . error ) . toEqual ( "'* ' is not a valid key for class level permissions" ) ;
done ( ) ;
} )
} ) ;
2016-03-30 20:27:12 -04:00
2016-03-09 19:58:50 -05:00
it ( 'should throw with invalid value' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/AClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
classLevelPermissions : {
find : {
'*' : 1
} ,
}
}
} , ( error , response , body ) => {
expect ( body . error ) . toEqual ( "'1' is not a valid value for class level permissions find:*:1" ) ;
done ( ) ;
} )
} ) ;
2016-03-30 20:27:12 -04:00
2016-03-09 19:58:50 -05:00
it ( 'should throw with invalid value' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/AClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
classLevelPermissions : {
find : {
'*' : ""
} ,
}
}
} , ( error , response , body ) => {
2016-11-24 15:47:41 -05:00
expect ( body . error ) . toEqual ( "'' is not a valid value for class level permissions find:*:" ) ;
2016-03-09 19:58:50 -05:00
done ( ) ;
} )
} ) ;
2016-03-30 20:27:12 -04:00
2016-03-09 21:40:11 -05:00
function setPermissionsOnClass ( className , permissions , doPut ) {
let op = request . post ;
2016-03-30 20:27:12 -04:00
if ( doPut )
2016-03-09 21:40:11 -05:00
{
op = request . put ;
}
return new Promise ( ( resolve , reject ) => {
2016-11-24 15:47:41 -05:00
op ( {
2017-01-11 12:31:40 -08:00
url : 'http://localhost:8378/1/schemas/' + className ,
2016-11-24 15:47:41 -05:00
headers : masterKeyHeaders ,
json : true ,
body : {
classLevelPermissions : permissions
}
} , ( error , response , body ) => {
if ( error ) {
return reject ( error ) ;
}
if ( body . error ) {
return reject ( body ) ;
}
return resolve ( body ) ;
} )
2016-03-09 21:40:11 -05:00
} ) ;
}
2016-03-30 20:27:12 -04:00
2016-08-15 16:48:39 -04:00
it ( 'validate CLP 1' , done => {
2016-12-07 15:17:05 -08:00
const user = new Parse . User ( ) ;
2016-03-09 21:40:11 -05:00
user . setUsername ( 'user' ) ;
user . setPassword ( 'user' ) ;
2016-03-30 20:27:12 -04:00
2016-12-07 15:17:05 -08:00
const admin = new Parse . User ( ) ;
2016-03-09 21:40:11 -05:00
admin . setUsername ( 'admin' ) ;
admin . setPassword ( 'admin' ) ;
2016-03-30 20:27:12 -04:00
2016-12-07 15:17:05 -08:00
const role = new Parse . Role ( 'admin' , new Parse . ACL ( ) ) ;
2016-03-30 20:27:12 -04:00
2016-03-09 21:40:11 -05:00
setPermissionsOnClass ( 'AClass' , {
'find' : {
'role:admin' : true
}
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-03-09 21:40:11 -05:00
return Parse . Object . saveAll ( [ user , admin , role ] , { useMasterKey : true } ) ;
} ) . then ( ( ) => {
role . relation ( 'users' ) . add ( admin ) ;
return role . save ( null , { useMasterKey : true } ) ;
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
return Parse . User . logIn ( 'user' , 'user' ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const obj = new Parse . Object ( 'AClass' ) ;
2016-06-06 12:31:50 -04:00
return obj . save ( null , { useMasterKey : true } ) ;
2016-03-09 21:40:11 -05:00
} )
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( 'AClass' ) ;
2016-11-24 15:47:41 -05:00
return query . find ( ) . then ( ( ) => {
2016-03-09 21:40:11 -05:00
fail ( 'Use should hot be able to find!' )
2016-11-24 15:47:41 -05:00
} , ( err ) => {
2016-07-08 03:30:29 +12:00
expect ( err . message ) . toEqual ( 'Permission denied for action find on class AClass.' ) ;
2016-03-09 21:40:11 -05:00
return Promise . resolve ( ) ;
} )
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-03-09 21:40:11 -05:00
return Parse . User . logIn ( 'admin' , 'admin' ) ;
2016-12-02 16:11:54 -08:00
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( 'AClass' ) ;
2016-03-09 21:40:11 -05:00
return query . find ( ) ;
} ) . then ( ( results ) => {
expect ( results . length ) . toBe ( 1 ) ;
done ( ) ;
2016-12-02 16:11:54 -08:00
} ) . catch ( ( err ) => {
2016-08-20 16:07:48 -04:00
jfail ( err ) ;
2016-03-09 21:40:11 -05:00
done ( ) ;
} )
} ) ;
2016-03-30 20:27:12 -04:00
2016-08-15 16:48:39 -04:00
it ( 'validate CLP 2' , done => {
2016-12-07 15:17:05 -08:00
const user = new Parse . User ( ) ;
2016-03-09 21:40:11 -05:00
user . setUsername ( 'user' ) ;
user . setPassword ( 'user' ) ;
2016-03-30 20:27:12 -04:00
2016-12-07 15:17:05 -08:00
const admin = new Parse . User ( ) ;
2016-03-09 21:40:11 -05:00
admin . setUsername ( 'admin' ) ;
admin . setPassword ( 'admin' ) ;
2016-03-30 20:27:12 -04:00
2016-12-07 15:17:05 -08:00
const role = new Parse . Role ( 'admin' , new Parse . ACL ( ) ) ;
2016-03-30 20:27:12 -04:00
2016-03-09 21:40:11 -05:00
setPermissionsOnClass ( 'AClass' , {
'find' : {
'role:admin' : true
}
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-03-09 21:40:11 -05:00
return Parse . Object . saveAll ( [ user , admin , role ] , { useMasterKey : true } ) ;
} ) . then ( ( ) => {
role . relation ( 'users' ) . add ( admin ) ;
return role . save ( null , { useMasterKey : true } ) ;
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
return Parse . User . logIn ( 'user' , 'user' ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const obj = new Parse . Object ( 'AClass' ) ;
2016-06-06 12:31:50 -04:00
return obj . save ( null , { useMasterKey : true } ) ;
2016-03-09 21:40:11 -05:00
} )
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( 'AClass' ) ;
2016-11-24 15:47:41 -05:00
return query . find ( ) . then ( ( ) => {
2016-03-09 21:40:11 -05:00
fail ( 'User should not be able to find!' )
2016-11-24 15:47:41 -05:00
} , ( err ) => {
2016-07-08 03:30:29 +12:00
expect ( err . message ) . toEqual ( 'Permission denied for action find on class AClass.' ) ;
2016-03-09 21:40:11 -05:00
return Promise . resolve ( ) ;
} )
} ) . then ( ( ) => {
// let everyone see it now
return setPermissionsOnClass ( 'AClass' , {
'find' : {
'role:admin' : true ,
'*' : true
}
} , true ) ;
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( 'AClass' ) ;
2016-03-09 21:40:11 -05:00
return query . find ( ) . then ( ( result ) => {
expect ( result . length ) . toBe ( 1 ) ;
2016-11-24 15:47:41 -05:00
} , ( ) => {
2016-03-09 21:40:11 -05:00
fail ( 'User should be able to find!' )
done ( ) ;
} ) ;
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-03-09 21:40:11 -05:00
return Parse . User . logIn ( 'admin' , 'admin' ) ;
2016-12-02 16:11:54 -08:00
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( 'AClass' ) ;
2016-03-09 21:40:11 -05:00
return query . find ( ) ;
} ) . then ( ( results ) => {
expect ( results . length ) . toBe ( 1 ) ;
done ( ) ;
2016-12-02 16:11:54 -08:00
} ) . catch ( ( err ) => {
2016-08-20 16:07:48 -04:00
jfail ( err ) ;
2016-03-09 21:40:11 -05:00
done ( ) ;
} )
} ) ;
2016-03-30 20:27:12 -04:00
2016-08-20 16:07:48 -04:00
it ( 'validate CLP 3' , done => {
2016-12-07 15:17:05 -08:00
const user = new Parse . User ( ) ;
2016-03-09 21:40:11 -05:00
user . setUsername ( 'user' ) ;
user . setPassword ( 'user' ) ;
2016-03-30 20:27:12 -04:00
2016-12-07 15:17:05 -08:00
const admin = new Parse . User ( ) ;
2016-03-09 21:40:11 -05:00
admin . setUsername ( 'admin' ) ;
admin . setPassword ( 'admin' ) ;
2016-03-30 20:27:12 -04:00
2016-12-07 15:17:05 -08:00
const role = new Parse . Role ( 'admin' , new Parse . ACL ( ) ) ;
2016-03-30 20:27:12 -04:00
2016-03-09 21:40:11 -05:00
setPermissionsOnClass ( 'AClass' , {
'find' : {
'role:admin' : true
}
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-03-09 21:40:11 -05:00
return Parse . Object . saveAll ( [ user , admin , role ] , { useMasterKey : true } ) ;
} ) . then ( ( ) => {
role . relation ( 'users' ) . add ( admin ) ;
return role . save ( null , { useMasterKey : true } ) ;
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
return Parse . User . logIn ( 'user' , 'user' ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const obj = new Parse . Object ( 'AClass' ) ;
2016-06-06 12:31:50 -04:00
return obj . save ( null , { useMasterKey : true } ) ;
2016-03-09 21:40:11 -05:00
} )
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( 'AClass' ) ;
2016-11-24 15:47:41 -05:00
return query . find ( ) . then ( ( ) => {
2016-03-09 21:40:11 -05:00
fail ( 'User should not be able to find!' )
2016-11-24 15:47:41 -05:00
} , ( err ) => {
2016-07-08 03:30:29 +12:00
expect ( err . message ) . toEqual ( 'Permission denied for action find on class AClass.' ) ;
2016-03-09 21:40:11 -05:00
return Promise . resolve ( ) ;
} )
} ) . then ( ( ) => {
// delete all CLP
return setPermissionsOnClass ( 'AClass' , null , true ) ;
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( 'AClass' ) ;
2016-03-09 21:40:11 -05:00
return query . find ( ) . then ( ( result ) => {
expect ( result . length ) . toBe ( 1 ) ;
2016-11-24 15:47:41 -05:00
} , ( ) => {
2016-03-09 21:40:11 -05:00
fail ( 'User should be able to find!' )
done ( ) ;
} ) ;
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-03-09 21:40:11 -05:00
return Parse . User . logIn ( 'admin' , 'admin' ) ;
2016-12-02 16:11:54 -08:00
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( 'AClass' ) ;
2016-03-09 21:40:11 -05:00
return query . find ( ) ;
} ) . then ( ( results ) => {
expect ( results . length ) . toBe ( 1 ) ;
done ( ) ;
2016-08-20 16:07:48 -04:00
} ) . catch ( ( err ) => {
jfail ( err ) ;
2016-03-09 21:40:11 -05:00
done ( ) ;
2016-03-10 18:02:29 -05:00
} ) ;
2016-03-09 21:40:11 -05:00
} ) ;
2016-03-30 20:27:12 -04:00
2016-08-15 16:48:39 -04:00
it ( 'validate CLP 4' , done => {
2016-12-07 15:17:05 -08:00
const user = new Parse . User ( ) ;
2016-03-09 21:40:11 -05:00
user . setUsername ( 'user' ) ;
user . setPassword ( 'user' ) ;
2016-03-30 20:27:12 -04:00
2016-12-07 15:17:05 -08:00
const admin = new Parse . User ( ) ;
2016-03-09 21:40:11 -05:00
admin . setUsername ( 'admin' ) ;
admin . setPassword ( 'admin' ) ;
2016-03-30 20:27:12 -04:00
2016-12-07 15:17:05 -08:00
const role = new Parse . Role ( 'admin' , new Parse . ACL ( ) ) ;
2016-03-30 20:27:12 -04:00
2016-03-09 21:40:11 -05:00
setPermissionsOnClass ( 'AClass' , {
'find' : {
'role:admin' : true
}
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-03-09 21:40:11 -05:00
return Parse . Object . saveAll ( [ user , admin , role ] , { useMasterKey : true } ) ;
} ) . then ( ( ) => {
role . relation ( 'users' ) . add ( admin ) ;
return role . save ( null , { useMasterKey : true } ) ;
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
return Parse . User . logIn ( 'user' , 'user' ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const obj = new Parse . Object ( 'AClass' ) ;
2016-06-06 12:31:50 -04:00
return obj . save ( null , { useMasterKey : true } ) ;
2016-03-09 21:40:11 -05:00
} )
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( 'AClass' ) ;
2016-11-24 15:47:41 -05:00
return query . find ( ) . then ( ( ) => {
2016-03-09 21:40:11 -05:00
fail ( 'User should not be able to find!' )
2016-11-24 15:47:41 -05:00
} , ( err ) => {
2016-07-08 03:30:29 +12:00
expect ( err . message ) . toEqual ( 'Permission denied for action find on class AClass.' ) ;
2016-03-09 21:40:11 -05:00
return Promise . resolve ( ) ;
} )
} ) . then ( ( ) => {
// borked CLP should not affec security
return setPermissionsOnClass ( 'AClass' , {
'found' : {
2016-03-30 20:27:12 -04:00
'role:admin' : true
2016-03-09 21:40:11 -05:00
}
2016-11-24 15:47:41 -05:00
} , true ) . then ( ( ) => {
2016-03-09 21:40:11 -05:00
fail ( "Should not be able to save a borked CLP" ) ;
2016-11-24 15:47:41 -05:00
} , ( ) => {
2016-03-09 21:40:11 -05:00
return Promise . resolve ( ) ;
} )
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( 'AClass' ) ;
2016-11-24 15:47:41 -05:00
return query . find ( ) . then ( ( ) => {
2016-03-09 21:40:11 -05:00
fail ( 'User should not be able to find!' )
2016-11-24 15:47:41 -05:00
} , ( err ) => {
2016-07-08 03:30:29 +12:00
expect ( err . message ) . toEqual ( 'Permission denied for action find on class AClass.' ) ;
2016-03-09 21:40:11 -05:00
return Promise . resolve ( ) ;
} ) ;
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-03-09 21:40:11 -05:00
return Parse . User . logIn ( 'admin' , 'admin' ) ;
2016-12-02 16:11:54 -08:00
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( 'AClass' ) ;
2016-03-09 21:40:11 -05:00
return query . find ( ) ;
} ) . then ( ( results ) => {
expect ( results . length ) . toBe ( 1 ) ;
done ( ) ;
2016-12-02 16:11:54 -08:00
} ) . catch ( ( err ) => {
2016-08-20 16:07:48 -04:00
jfail ( err ) ;
2016-03-09 21:40:11 -05:00
done ( ) ;
} )
} ) ;
2016-03-30 20:27:12 -04:00
2016-08-15 16:48:39 -04:00
it ( 'validate CLP 5' , done => {
2016-12-07 15:17:05 -08:00
const user = new Parse . User ( ) ;
2016-03-10 18:02:29 -05:00
user . setUsername ( 'user' ) ;
user . setPassword ( 'user' ) ;
2016-03-30 20:27:12 -04:00
2016-12-07 15:17:05 -08:00
const user2 = new Parse . User ( ) ;
2016-03-10 18:02:29 -05:00
user2 . setUsername ( 'user2' ) ;
user2 . setPassword ( 'user2' ) ;
2016-12-07 15:17:05 -08:00
const admin = new Parse . User ( ) ;
2016-03-10 18:02:29 -05:00
admin . setUsername ( 'admin' ) ;
admin . setPassword ( 'admin' ) ;
2016-03-30 20:27:12 -04:00
2016-12-07 15:17:05 -08:00
const role = new Parse . Role ( 'admin' , new Parse . ACL ( ) ) ;
2016-03-30 20:27:12 -04:00
2016-11-24 15:47:41 -05:00
Promise . resolve ( ) . then ( ( ) => {
2016-03-10 18:02:29 -05:00
return Parse . Object . saveAll ( [ user , user2 , admin , role ] , { useMasterKey : true } ) ;
} ) . then ( ( ) => {
role . relation ( 'users' ) . add ( admin ) ;
2016-11-24 15:47:41 -05:00
return role . save ( null , { useMasterKey : true } ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const perm = {
2016-03-10 19:20:05 -05:00
find : { }
2016-03-10 18:02:29 -05:00
} ;
// let the user find
perm [ 'find' ] [ user . id ] = true ;
return setPermissionsOnClass ( 'AClass' , perm ) ;
} )
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
return Parse . User . logIn ( 'user' , 'user' ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const obj = new Parse . Object ( 'AClass' ) ;
2016-03-10 18:02:29 -05:00
return obj . save ( ) ;
} )
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( 'AClass' ) ;
2016-03-10 18:02:29 -05:00
return query . find ( ) . then ( ( res ) => {
expect ( res . length ) . toEqual ( 1 ) ;
2016-11-24 15:47:41 -05:00
} , ( ) => {
fail ( 'User should be able to find!' )
2016-03-10 18:02:29 -05:00
return Promise . resolve ( ) ;
} )
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-03-10 18:02:29 -05:00
return Parse . User . logIn ( 'admin' , 'admin' ) ;
2016-12-02 16:11:54 -08:00
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( 'AClass' ) ;
2016-03-10 18:02:29 -05:00
return query . find ( ) ;
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-03-10 18:02:29 -05:00
fail ( "should not be able to read!" ) ;
return Promise . resolve ( ) ;
} , ( err ) => {
2016-07-08 03:30:29 +12:00
expect ( err . message ) . toEqual ( 'Permission denied for action create on class AClass.' ) ;
2016-03-10 18:02:29 -05:00
return Promise . resolve ( ) ;
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-03-10 18:02:29 -05:00
return Parse . User . logIn ( 'user2' , 'user2' ) ;
2016-12-02 16:11:54 -08:00
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( 'AClass' ) ;
2016-03-10 18:02:29 -05:00
return query . find ( ) ;
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-03-10 18:02:29 -05:00
fail ( "should not be able to read!" ) ;
return Promise . resolve ( ) ;
} , ( err ) => {
2016-07-08 03:30:29 +12:00
expect ( err . message ) . toEqual ( 'Permission denied for action find on class AClass.' ) ;
2016-03-10 18:02:29 -05:00
return Promise . resolve ( ) ;
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-03-10 18:02:29 -05:00
done ( ) ;
} ) ;
2016-03-30 20:27:12 -04:00
} ) ;
2016-11-24 15:47:41 -05:00
it ( 'can query with include and CLP (issue #2005)' , ( done ) => {
2016-09-24 14:54:31 -04:00
setPermissionsOnClass ( 'AnotherObject' , {
get : { "*" : true } ,
find : { } ,
create : { '*' : true } ,
update : { '*' : true } ,
delete : { '*' : true } ,
addField : { '*' : true }
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const obj = new Parse . Object ( 'AnObject' ) ;
const anotherObject = new Parse . Object ( 'AnotherObject' ) ;
2016-09-24 14:54:31 -04:00
return obj . save ( {
anotherObject
} )
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( 'AnObject' ) ;
2016-09-24 14:54:31 -04:00
query . include ( 'anotherObject' ) ;
return query . find ( ) ;
2016-11-24 15:47:41 -05:00
} ) . then ( ( res ) => {
2016-09-24 14:54:31 -04:00
expect ( res . length ) . toBe ( 1 ) ;
expect ( res [ 0 ] . get ( 'anotherObject' ) ) . not . toBeUndefined ( ) ;
done ( ) ;
2016-11-24 15:47:41 -05:00
} ) . catch ( ( err ) => {
2016-09-24 14:54:31 -04:00
jfail ( err ) ;
done ( ) ;
} )
} ) ;
2016-11-24 15:47:41 -05:00
it ( 'can add field as master (issue #1257)' , ( done ) => {
2016-03-30 20:27:12 -04:00
setPermissionsOnClass ( 'AClass' , {
'addField' : { }
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-03-30 20:27:12 -04:00
var obj = new Parse . Object ( 'AClass' ) ;
obj . set ( 'key' , 'value' ) ;
return obj . save ( null , { useMasterKey : true } )
2016-11-24 15:47:41 -05:00
} ) . then ( ( obj ) => {
2016-03-30 20:27:12 -04:00
expect ( obj . get ( 'key' ) ) . toEqual ( 'value' ) ;
done ( ) ;
2016-11-24 15:47:41 -05:00
} , ( ) => {
2016-03-30 20:27:12 -04:00
fail ( 'should not fail' ) ;
done ( ) ;
} ) ;
2016-04-04 08:36:40 -04:00
} ) ;
2016-11-24 15:47:41 -05:00
it ( 'can login when addFields is false (issue #1355)' , ( done ) => {
2016-04-04 08:36:40 -04:00
setPermissionsOnClass ( '_User' , {
2016-06-06 12:31:50 -04:00
'create' : { '*' : true } ,
2016-04-04 08:36:40 -04:00
'addField' : { }
2016-06-16 15:39:05 -07:00
} , true ) . then ( ( ) => {
2016-04-04 08:36:40 -04:00
return Parse . User . signUp ( 'foo' , 'bar' ) ;
} ) . then ( ( user ) => {
expect ( user . getUsername ( ) ) . toBe ( 'foo' ) ;
done ( )
2016-06-16 15:39:05 -07:00
} , error => {
fail ( JSON . stringify ( error ) ) ;
2016-04-04 08:36:40 -04:00
done ( ) ;
} )
2016-03-30 20:27:12 -04:00
} )
2016-05-26 16:15:54 -07:00
2016-08-18 18:05:26 -04:00
it ( 'gives correct response when deleting a schema with CLPs (regression test #1919)' , done => {
2016-05-26 16:15:54 -07:00
new Parse . Object ( 'MyClass' ) . save ( { data : 'foo' } )
2017-06-20 09:15:26 -07:00
. then ( obj => obj . destroy ( ) )
. then ( ( ) => setPermissionsOnClass ( 'MyClass' , { find : { } , get : { } } , true ) )
. then ( ( ) => {
request . del ( {
url : 'http://localhost:8378/1/schemas/MyClass' ,
headers : masterKeyHeaders ,
json : true ,
} , ( error , response ) => {
expect ( response . statusCode ) . toEqual ( 200 ) ;
expect ( response . body ) . toEqual ( { } ) ;
done ( ) ;
} ) ;
2016-05-26 16:15:54 -07:00
} ) ;
} ) ;
2016-06-06 12:31:50 -04:00
2016-08-15 16:48:39 -04:00
it ( "regression test for #1991" , done => {
2016-12-07 15:17:05 -08:00
const user = new Parse . User ( ) ;
2016-06-06 12:31:50 -04:00
user . setUsername ( 'user' ) ;
user . setPassword ( 'user' ) ;
2016-12-07 15:17:05 -08:00
const role = new Parse . Role ( 'admin' , new Parse . ACL ( ) ) ;
const obj = new Parse . Object ( 'AnObject' ) ;
2016-06-06 12:31:50 -04:00
Parse . Object . saveAll ( [ user , role ] ) . then ( ( ) => {
role . relation ( 'users' ) . add ( user ) ;
return role . save ( null , { useMasterKey : true } ) ;
} ) . then ( ( ) => {
return setPermissionsOnClass ( 'AnObject' , {
'get' : { "*" : true } ,
'find' : { "*" : true } ,
'create' : { '*' : true } ,
'update' : { 'role:admin' : true } ,
'delete' : { 'role:admin' : true }
} )
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-06-06 12:31:50 -04:00
return obj . save ( ) ;
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-06-06 12:31:50 -04:00
return Parse . User . logIn ( 'user' , 'user' )
} ) . then ( ( ) => {
return obj . destroy ( ) ;
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( 'AnObject' ) ;
2016-06-06 12:31:50 -04:00
return query . find ( ) ;
} ) . then ( ( results ) => {
expect ( results . length ) . toBe ( 0 ) ;
done ( ) ;
2016-11-24 15:47:41 -05:00
} ) . catch ( ( err ) => {
2016-06-06 12:31:50 -04:00
fail ( 'should not fail' ) ;
2016-08-15 16:48:39 -04:00
jfail ( err ) ;
2016-06-06 12:31:50 -04:00
done ( ) ;
} ) ;
} ) ;
2016-09-09 14:43:59 -04:00
2016-11-24 15:47:41 -05:00
it ( 'regression test for #2246' , done => {
2016-12-07 15:17:05 -08:00
const profile = new Parse . Object ( 'UserProfile' ) ;
const user = new Parse . User ( ) ;
2016-09-09 14:43:59 -04:00
function initialize ( ) {
return user . save ( {
username : 'user' ,
password : 'password'
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
return profile . save ( { user } ) . then ( ( ) => {
return user . save ( {
2016-09-09 14:43:59 -04:00
userProfile : profile
} , { useMasterKey : true } ) ;
} ) ;
} ) ;
}
2016-11-24 15:47:41 -05:00
initialize ( ) . then ( ( ) => {
2016-09-09 14:43:59 -04:00
return setPermissionsOnClass ( 'UserProfile' , {
'readUserFields' : [ 'user' ] ,
'writeUserFields' : [ 'user' ]
} , true ) ;
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-09-09 14:43:59 -04:00
return Parse . User . logIn ( 'user' , 'password' )
2016-11-24 15:47:41 -05:00
} ) . then ( ( ) => {
2016-12-07 15:17:05 -08:00
const query = new Parse . Query ( '_User' ) ;
2016-09-09 14:43:59 -04:00
query . include ( 'userProfile' ) ;
return query . get ( user . id ) ;
2016-11-24 15:47:41 -05:00
} ) . then ( ( user ) => {
2016-09-09 14:43:59 -04:00
expect ( user . get ( 'userProfile' ) ) . not . toBeUndefined ( ) ;
done ( ) ;
2016-11-24 15:47:41 -05:00
} , ( err ) => {
2016-09-09 14:43:59 -04:00
jfail ( err ) ;
done ( ) ;
} ) ;
} ) ;
2017-11-25 13:55:34 -06:00
it ( 'cannot create index if field does not exist' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : { } ,
} , ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
indexes : {
name1 : { aString : 1 } ,
}
}
} , ( error , response , body ) => {
expect ( body . code ) . toBe ( Parse . Error . INVALID _QUERY ) ;
expect ( body . error ) . toBe ( 'Field aString does not exist, cannot add index.' ) ;
done ( ) ;
} ) ;
} )
} ) ;
it ( 'cannot create compound index if field does not exist' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : { } ,
} , ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
aString : { type : 'String' }
} ,
indexes : {
name1 : { aString : 1 , bString : 1 } ,
}
}
} , ( error , response , body ) => {
expect ( body . code ) . toBe ( Parse . Error . INVALID _QUERY ) ;
expect ( body . error ) . toBe ( 'Field bString does not exist, cannot add index.' ) ;
done ( ) ;
} ) ;
} )
} ) ;
it ( 'allows add index when you create a class' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas' ,
headers : masterKeyHeaders ,
json : true ,
body : {
className : "NewClass" ,
fields : {
aString : { type : 'String' }
} ,
indexes : {
name1 : { aString : 1 } ,
} ,
}
} , ( error , response , body ) => {
expect ( body ) . toEqual ( {
className : 'NewClass' ,
fields : {
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
aString : { type : 'String' }
} ,
classLevelPermissions : defaultClassLevelPermissions ,
indexes : {
name1 : { aString : 1 } ,
} ,
} ) ;
config . database . adapter . getIndexes ( 'NewClass' ) . then ( ( indexes ) => {
expect ( indexes . length ) . toBe ( 2 ) ;
done ( ) ;
} ) ;
} ) ;
} ) ;
it ( 'empty index returns nothing' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas' ,
headers : masterKeyHeaders ,
json : true ,
body : {
className : "NewClass" ,
fields : {
aString : { type : 'String' }
} ,
indexes : { } ,
}
} , ( error , response , body ) => {
expect ( body ) . toEqual ( {
className : 'NewClass' ,
fields : {
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
aString : { type : 'String' }
} ,
classLevelPermissions : defaultClassLevelPermissions ,
} ) ;
done ( ) ;
} ) ;
} ) ;
it ( 'lets you add indexes' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : { } ,
} , ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
aString : { type : 'String' }
} ,
indexes : {
name1 : { aString : 1 } ,
} ,
}
} , ( error , response , body ) => {
expect ( dd ( body , {
className : 'NewClass' ,
fields : {
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
aString : { type : 'String' }
} ,
classLevelPermissions : defaultClassLevelPermissions ,
indexes : {
_id _ : { _id : 1 } ,
name1 : { aString : 1 } ,
}
} ) ) . toEqual ( undefined ) ;
request . get ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
} , ( error , response , body ) => {
expect ( body ) . toEqual ( {
className : 'NewClass' ,
fields : {
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
aString : { type : 'String' }
} ,
classLevelPermissions : defaultClassLevelPermissions ,
indexes : {
_id _ : { _id : 1 } ,
name1 : { aString : 1 } ,
}
} ) ;
config . database . adapter . getIndexes ( 'NewClass' ) . then ( ( indexes ) => {
expect ( indexes . length ) . toEqual ( 2 ) ;
done ( ) ;
} ) ;
} ) ;
} ) ;
} )
} ) ;
it ( 'lets you add multiple indexes' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : { } ,
} , ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
aString : { type : 'String' } ,
bString : { type : 'String' } ,
cString : { type : 'String' } ,
dString : { type : 'String' } ,
} ,
indexes : {
name1 : { aString : 1 } ,
name2 : { bString : 1 } ,
name3 : { cString : 1 , dString : 1 } ,
}
}
} , ( error , response , body ) => {
expect ( dd ( body , {
className : 'NewClass' ,
fields : {
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
aString : { type : 'String' } ,
bString : { type : 'String' } ,
cString : { type : 'String' } ,
dString : { type : 'String' } ,
} ,
classLevelPermissions : defaultClassLevelPermissions ,
indexes : {
_id _ : { _id : 1 } ,
name1 : { aString : 1 } ,
name2 : { bString : 1 } ,
name3 : { cString : 1 , dString : 1 } ,
}
} ) ) . toEqual ( undefined ) ;
request . get ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
} , ( error , response , body ) => {
expect ( body ) . toEqual ( {
className : 'NewClass' ,
fields : {
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
aString : { type : 'String' } ,
bString : { type : 'String' } ,
cString : { type : 'String' } ,
dString : { type : 'String' } ,
} ,
classLevelPermissions : defaultClassLevelPermissions ,
indexes : {
_id _ : { _id : 1 } ,
name1 : { aString : 1 } ,
name2 : { bString : 1 } ,
name3 : { cString : 1 , dString : 1 } ,
} ,
} ) ;
config . database . adapter . getIndexes ( 'NewClass' ) . then ( ( indexes ) => {
expect ( indexes . length ) . toEqual ( 4 ) ;
done ( ) ;
} ) ;
} ) ;
} ) ;
} )
} ) ;
it ( 'lets you delete indexes' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : { } ,
} , ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
aString : { type : 'String' } ,
} ,
indexes : {
name1 : { aString : 1 } ,
}
}
} , ( error , response , body ) => {
expect ( dd ( body , {
className : 'NewClass' ,
fields : {
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
aString : { type : 'String' } ,
} ,
classLevelPermissions : defaultClassLevelPermissions ,
indexes : {
_id _ : { _id : 1 } ,
name1 : { aString : 1 } ,
}
} ) ) . toEqual ( undefined ) ;
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
indexes : {
name1 : { _ _op : 'Delete' }
}
}
} , ( error , response , body ) => {
expect ( body ) . toEqual ( {
className : 'NewClass' ,
fields : {
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
aString : { type : 'String' } ,
} ,
classLevelPermissions : defaultClassLevelPermissions ,
indexes : {
_id _ : { _id : 1 } ,
}
} ) ;
config . database . adapter . getIndexes ( 'NewClass' ) . then ( ( indexes ) => {
expect ( indexes . length ) . toEqual ( 1 ) ;
done ( ) ;
} ) ;
} ) ;
} ) ;
} )
} ) ;
it ( 'lets you delete multiple indexes' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : { } ,
} , ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
aString : { type : 'String' } ,
bString : { type : 'String' } ,
cString : { type : 'String' } ,
} ,
indexes : {
name1 : { aString : 1 } ,
name2 : { bString : 1 } ,
name3 : { cString : 1 } ,
}
}
} , ( error , response , body ) => {
expect ( dd ( body , {
className : 'NewClass' ,
fields : {
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
aString : { type : 'String' } ,
bString : { type : 'String' } ,
cString : { type : 'String' } ,
} ,
classLevelPermissions : defaultClassLevelPermissions ,
indexes : {
_id _ : { _id : 1 } ,
name1 : { aString : 1 } ,
name2 : { bString : 1 } ,
name3 : { cString : 1 } ,
}
} ) ) . toEqual ( undefined ) ;
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
indexes : {
name1 : { _ _op : 'Delete' } ,
name2 : { _ _op : 'Delete' } ,
}
}
} , ( error , response , body ) => {
expect ( body ) . toEqual ( {
className : 'NewClass' ,
fields : {
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
aString : { type : 'String' } ,
bString : { type : 'String' } ,
cString : { type : 'String' } ,
} ,
classLevelPermissions : defaultClassLevelPermissions ,
indexes : {
_id _ : { _id : 1 } ,
name3 : { cString : 1 } ,
}
} ) ;
config . database . adapter . getIndexes ( 'NewClass' ) . then ( ( indexes ) => {
expect ( indexes . length ) . toEqual ( 2 ) ;
done ( ) ;
} ) ;
} ) ;
} ) ;
} )
} ) ;
it ( 'lets you add and delete indexes' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : { } ,
} , ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
aString : { type : 'String' } ,
bString : { type : 'String' } ,
cString : { type : 'String' } ,
dString : { type : 'String' } ,
} ,
indexes : {
name1 : { aString : 1 } ,
name2 : { bString : 1 } ,
name3 : { cString : 1 } ,
}
}
} , ( error , response , body ) => {
expect ( dd ( body , {
className : 'NewClass' ,
fields : {
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
aString : { type : 'String' } ,
bString : { type : 'String' } ,
cString : { type : 'String' } ,
dString : { type : 'String' } ,
} ,
classLevelPermissions : defaultClassLevelPermissions ,
indexes : {
_id _ : { _id : 1 } ,
name1 : { aString : 1 } ,
name2 : { bString : 1 } ,
name3 : { cString : 1 } ,
}
} ) ) . toEqual ( undefined ) ;
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
indexes : {
name1 : { _ _op : 'Delete' } ,
name2 : { _ _op : 'Delete' } ,
name4 : { dString : 1 } ,
}
}
} , ( error , response , body ) => {
expect ( body ) . toEqual ( {
className : 'NewClass' ,
fields : {
ACL : { type : 'ACL' } ,
createdAt : { type : 'Date' } ,
updatedAt : { type : 'Date' } ,
objectId : { type : 'String' } ,
aString : { type : 'String' } ,
bString : { type : 'String' } ,
cString : { type : 'String' } ,
dString : { type : 'String' } ,
} ,
classLevelPermissions : defaultClassLevelPermissions ,
indexes : {
_id _ : { _id : 1 } ,
name3 : { cString : 1 } ,
name4 : { dString : 1 } ,
}
} ) ;
config . database . adapter . getIndexes ( 'NewClass' ) . then ( ( indexes ) => {
expect ( indexes . length ) . toEqual ( 3 ) ;
done ( ) ;
} ) ;
} ) ;
} ) ;
} )
} ) ;
it ( 'cannot delete index that does not exist' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : { } ,
} , ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
indexes : {
unknownIndex : { _ _op : 'Delete' }
}
}
} , ( error , response , body ) => {
expect ( body . code ) . toBe ( Parse . Error . INVALID _QUERY ) ;
expect ( body . error ) . toBe ( 'Index unknownIndex does not exist, cannot delete.' ) ;
done ( ) ;
} ) ;
} )
} ) ;
it ( 'cannot update index that exist' , done => {
request . post ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : { } ,
} , ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
fields : {
aString : { type : 'String' } ,
} ,
indexes : {
name1 : { aString : 1 }
}
}
} , ( ) => {
request . put ( {
url : 'http://localhost:8378/1/schemas/NewClass' ,
headers : masterKeyHeaders ,
json : true ,
body : {
indexes : {
name1 : { field2 : 1 }
}
}
} , ( error , response , body ) => {
expect ( body . code ) . toBe ( Parse . Error . INVALID _QUERY ) ;
expect ( body . error ) . toBe ( 'Index name1 exists, cannot update.' ) ;
done ( ) ;
} ) ;
} ) ;
} )
} ) ;
it _exclude _dbs ( [ 'postgres' ] ) ( 'get indexes on startup' , ( done ) => {
const obj = new Parse . Object ( 'TestObject' ) ;
obj . save ( ) . then ( ( ) => {
return reconfigureServer ( {
appId : 'test' ,
restAPIKey : 'test' ,
publicServerURL : 'http://localhost:8378/1' ,
} ) ;
} ) . then ( ( ) => {
request . get ( {
url : 'http://localhost:8378/1/schemas/TestObject' ,
headers : masterKeyHeaders ,
json : true ,
} , ( error , response , body ) => {
expect ( body . indexes . _id _ ) . toBeDefined ( ) ;
done ( ) ;
} ) ;
} ) ;
} ) ;
it _exclude _dbs ( [ 'postgres' ] ) ( 'get compound indexes on startup' , ( done ) => {
const obj = new Parse . Object ( 'TestObject' ) ;
obj . set ( 'subject' , 'subject' ) ;
obj . set ( 'comment' , 'comment' ) ;
obj . save ( ) . then ( ( ) => {
return config . database . adapter . createIndex ( 'TestObject' , { subject : 'text' , comment : 'text' } ) ;
} ) . then ( ( ) => {
return reconfigureServer ( {
appId : 'test' ,
restAPIKey : 'test' ,
publicServerURL : 'http://localhost:8378/1' ,
} ) ;
} ) . then ( ( ) => {
request . get ( {
url : 'http://localhost:8378/1/schemas/TestObject' ,
headers : masterKeyHeaders ,
json : true ,
} , ( error , response , body ) => {
expect ( body . indexes . _id _ ) . toBeDefined ( ) ;
expect ( body . indexes . _id _ . _id ) . toEqual ( 1 ) ;
expect ( body . indexes . subject _text _comment _text ) . toBeDefined ( ) ;
expect ( body . indexes . subject _text _comment _text . subject ) . toEqual ( 'text' ) ;
expect ( body . indexes . subject _text _comment _text . comment ) . toEqual ( 'text' ) ;
done ( ) ;
} ) ;
} ) ;
} ) ;
2016-02-03 11:55:44 -08:00
} ) ;