Live query CLP (#4387)
* Auth module refactoring in order to be reusable * Ensure cache controller is properly forwarded from helpers * Nits * Adds support for static validation * Adds support for CLP in Live query (no support for roles yet) * Adds e2e test to validate liveQuery hooks is properly called * Adds tests over LiveQueryController to ensure data is correctly transmitted * nits * Fixes for flow types * Removes usage of Parse.Promise * Use the Auth module for authentication and caches * Cleaner implementation of getting auth * Adds authCache that stores auth promises * Proper testing of the caching * nits
This commit is contained in:
@@ -1335,7 +1335,7 @@ class DatabaseController {
|
||||
}
|
||||
|
||||
addPointerPermissions(
|
||||
schema: any,
|
||||
schema: SchemaController.SchemaController,
|
||||
className: string,
|
||||
operation: string,
|
||||
query: any,
|
||||
@@ -1343,10 +1343,10 @@ class DatabaseController {
|
||||
) {
|
||||
// Check if class has public permission for operation
|
||||
// If the BaseCLP pass, let go through
|
||||
if (schema.testBaseCLP(className, aclGroup, operation)) {
|
||||
if (schema.testPermissionsForClassName(className, aclGroup, operation)) {
|
||||
return query;
|
||||
}
|
||||
const perms = schema.schemaData[className].classLevelPermissions;
|
||||
const perms = schema.getClassLevelPermissions(className);
|
||||
const field =
|
||||
['get', 'find'].indexOf(operation) > -1
|
||||
? 'readUserFields'
|
||||
|
||||
@@ -16,19 +16,37 @@ export class LiveQueryController {
|
||||
this.liveQueryPublisher = new ParseCloudCodePublisher(config);
|
||||
}
|
||||
|
||||
onAfterSave(className: string, currentObject: any, originalObject: any) {
|
||||
onAfterSave(
|
||||
className: string,
|
||||
currentObject: any,
|
||||
originalObject: any,
|
||||
classLevelPermissions: ?any
|
||||
) {
|
||||
if (!this.hasLiveQuery(className)) {
|
||||
return;
|
||||
}
|
||||
const req = this._makePublisherRequest(currentObject, originalObject);
|
||||
const req = this._makePublisherRequest(
|
||||
currentObject,
|
||||
originalObject,
|
||||
classLevelPermissions
|
||||
);
|
||||
this.liveQueryPublisher.onCloudCodeAfterSave(req);
|
||||
}
|
||||
|
||||
onAfterDelete(className: string, currentObject: any, originalObject: any) {
|
||||
onAfterDelete(
|
||||
className: string,
|
||||
currentObject: any,
|
||||
originalObject: any,
|
||||
classLevelPermissions: any
|
||||
) {
|
||||
if (!this.hasLiveQuery(className)) {
|
||||
return;
|
||||
}
|
||||
const req = this._makePublisherRequest(currentObject, originalObject);
|
||||
const req = this._makePublisherRequest(
|
||||
currentObject,
|
||||
originalObject,
|
||||
classLevelPermissions
|
||||
);
|
||||
this.liveQueryPublisher.onCloudCodeAfterDelete(req);
|
||||
}
|
||||
|
||||
@@ -36,13 +54,20 @@ export class LiveQueryController {
|
||||
return this.classNames.has(className);
|
||||
}
|
||||
|
||||
_makePublisherRequest(currentObject: any, originalObject: any): any {
|
||||
_makePublisherRequest(
|
||||
currentObject: any,
|
||||
originalObject: any,
|
||||
classLevelPermissions: ?any
|
||||
): any {
|
||||
const req = {
|
||||
object: currentObject,
|
||||
};
|
||||
if (currentObject) {
|
||||
req.original = originalObject;
|
||||
}
|
||||
if (classLevelPermissions) {
|
||||
req.classLevelPermissions = classLevelPermissions;
|
||||
}
|
||||
return req;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1122,18 +1122,28 @@ export default class SchemaController {
|
||||
return Promise.resolve(this);
|
||||
}
|
||||
|
||||
// Validates the base CLP for an operation
|
||||
testBaseCLP(className: string, aclGroup: string[], operation: string) {
|
||||
const classSchema = this.schemaData[className];
|
||||
if (
|
||||
!classSchema ||
|
||||
!classSchema.classLevelPermissions ||
|
||||
!classSchema.classLevelPermissions[operation]
|
||||
) {
|
||||
testPermissionsForClassName(
|
||||
className: string,
|
||||
aclGroup: string[],
|
||||
operation: string
|
||||
) {
|
||||
return SchemaController.testPermissions(
|
||||
this.getClassLevelPermissions(className),
|
||||
aclGroup,
|
||||
operation
|
||||
);
|
||||
}
|
||||
|
||||
// Tests that the class level permission let pass the operation for a given aclGroup
|
||||
static testPermissions(
|
||||
classPermissions: ?any,
|
||||
aclGroup: string[],
|
||||
operation: string
|
||||
): boolean {
|
||||
if (!classPermissions || !classPermissions[operation]) {
|
||||
return true;
|
||||
}
|
||||
const perms = classSchema.classLevelPermissions[operation];
|
||||
// Handle the public scenario quickly
|
||||
const perms = classPermissions[operation];
|
||||
if (perms['*']) {
|
||||
return true;
|
||||
}
|
||||
@@ -1149,21 +1159,22 @@ export default class SchemaController {
|
||||
}
|
||||
|
||||
// Validates an operation passes class-level-permissions set in the schema
|
||||
validatePermission(className: string, aclGroup: string[], operation: string) {
|
||||
if (this.testBaseCLP(className, aclGroup, operation)) {
|
||||
static validatePermission(
|
||||
classPermissions: ?any,
|
||||
className: string,
|
||||
aclGroup: string[],
|
||||
operation: string
|
||||
) {
|
||||
if (
|
||||
SchemaController.testPermissions(classPermissions, aclGroup, operation)
|
||||
) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
const classSchema = this.schemaData[className];
|
||||
if (
|
||||
!classSchema ||
|
||||
!classSchema.classLevelPermissions ||
|
||||
!classSchema.classLevelPermissions[operation]
|
||||
) {
|
||||
|
||||
if (!classPermissions || !classPermissions[operation]) {
|
||||
return true;
|
||||
}
|
||||
const classPerms = classSchema.classLevelPermissions;
|
||||
const perms = classSchema.classLevelPermissions[operation];
|
||||
|
||||
const perms = classPermissions[operation];
|
||||
// If only for authenticated users
|
||||
// make sure we have an aclGroup
|
||||
if (perms['requiresAuthentication']) {
|
||||
@@ -1201,8 +1212,8 @@ export default class SchemaController {
|
||||
|
||||
// Process the readUserFields later
|
||||
if (
|
||||
Array.isArray(classPerms[permissionField]) &&
|
||||
classPerms[permissionField].length > 0
|
||||
Array.isArray(classPermissions[permissionField]) &&
|
||||
classPermissions[permissionField].length > 0
|
||||
) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
@@ -1212,6 +1223,23 @@ export default class SchemaController {
|
||||
);
|
||||
}
|
||||
|
||||
// Validates an operation passes class-level-permissions set in the schema
|
||||
validatePermission(className: string, aclGroup: string[], operation: string) {
|
||||
return SchemaController.validatePermission(
|
||||
this.getClassLevelPermissions(className),
|
||||
className,
|
||||
aclGroup,
|
||||
operation
|
||||
);
|
||||
}
|
||||
|
||||
getClassLevelPermissions(className: string): any {
|
||||
return (
|
||||
this.schemaData[className] &&
|
||||
this.schemaData[className].classLevelPermissions
|
||||
);
|
||||
}
|
||||
|
||||
// Returns the expected type for a className+key combination
|
||||
// or undefined if the schema is not set
|
||||
getExpectedType(
|
||||
|
||||
Reference in New Issue
Block a user