var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import DatabaseRequestType from "../../BaseDatabase/DatabaseRequestType";
import ColumnPermissions from "./ColumnPermission";
import DatabaseCommonInteractionPropsUtil, { PermissionType, } from "../../../../Types/BaseDatabase/DatabaseCommonInteractionPropsUtil";
import MultiSearch from "../../../../Types/BaseDatabase/MultiSearch";
import TableColumnType from "../../../../Types/Database/TableColumnType";
import BadDataException from "../../../../Types/Exception/BadDataException";
import NotAuthorizedException from "../../../../Types/Exception/NotAuthorizedException";
import CaptureSpan from "../../../Utils/Telemetry/CaptureSpan";
import { PermissionHelper, } from "../../../../Types/Permission";
import Typeof from "../../../../Types/Typeof";
export default class QueryPermission {
    static checkRelationQueryPermission(modelType, select, props) {
        const model = new modelType();
        const userPermissions = DatabaseCommonInteractionPropsUtil.getUserPermissions(props, PermissionType.Allow).map((i) => {
            return i.permission;
        });
        const excludedColumnNames = ColumnPermissions.getExcludedColumnNames();
        for (const key in select) {
            if (typeof select[key] === Typeof.Object) {
                const tableColumnMetadata = model.getTableColumnMetadata(key);
                if (!tableColumnMetadata.modelType) {
                    throw new BadDataException("Select not supported on " +
                        key +
                        " of " +
                        model.singularName +
                        " because this column modelType is not found.");
                }
                const relatedModel = new tableColumnMetadata.modelType();
                if (tableColumnMetadata.type === TableColumnType.Entity ||
                    tableColumnMetadata.type === TableColumnType.EntityArray) {
                    for (const innerKey in select[key]) {
                        // check for permissions.
                        if (typeof select[key][innerKey] === Typeof.Object) {
                            throw new BadDataException("You cannot query deep relations. Querying deep relations is not supported.");
                        }
                        const getRelatedTableColumnMetadata = relatedModel.getTableColumnMetadata(innerKey);
                        if (!getRelatedTableColumnMetadata) {
                            throw new BadDataException(`Column ${innerKey} not found on ${relatedModel.singularName}`);
                        }
                        if (!getRelatedTableColumnMetadata.canReadOnRelationQuery &&
                            !excludedColumnNames.includes(innerKey)) {
                            throw new BadDataException(`Column ${innerKey} on ${relatedModel.singularName} does not support read on relation query.`);
                        }
                        if (getRelatedTableColumnMetadata.canReadOnRelationQuery) {
                            continue;
                        }
                        // check if the user has permission to read this column
                        if (userPermissions) {
                            const hasPermission = relatedModel.hasReadPermissions(userPermissions, innerKey);
                            if (!hasPermission) {
                                let readPermissions = [];
                                if (relatedModel.getColumnAccessControlFor(innerKey)) {
                                    readPermissions =
                                        relatedModel.getColumnAccessControlFor(innerKey).read;
                                }
                                throw new NotAuthorizedException(`You do not have permissions to read ${relatedModel.singularName} on ${model.singularName}. You need one of these permissions: ${PermissionHelper.getPermissionTitles(readPermissions).join(", ")}`);
                            }
                        }
                    }
                }
            }
        }
    }
    static checkQueryPermission(modelType, query, props) {
        const model = new modelType();
        const userPermissions = DatabaseCommonInteractionPropsUtil.getUserPermissions(props, PermissionType.Allow);
        const canReadOnTheseColumns = ColumnPermissions.getModelColumnsByPermissions(modelType, userPermissions || [], DatabaseRequestType.Read);
        const tableColumns = model.getTableColumns().columns;
        const excludedColumnNames = ColumnPermissions.getExcludedColumnNames();
        // Now we need to check all columns.
        for (const key in query) {
            if (excludedColumnNames.includes(key)) {
                continue;
            }
            /*
             * MultiSearch is a synthetic operator: the key itself is not a column,
             * but the operator carries the list of fields it will ILIKE against
             * (QueryUtil.serializeQuery expands it into an OR over those fields).
             * Validate each inner field the same way we validate any other queried
             * column so a client can't search across columns the user can't read.
             */
            if (query[key] instanceof MultiSearch) {
                const multiSearch = query[key];
                for (const field of multiSearch.fields) {
                    if (excludedColumnNames.includes(field)) {
                        continue;
                    }
                    if (!tableColumns.includes(field)) {
                        throw new BadDataException(`Invalid column on ${model.singularName} - ${field}. Column does not exist.`);
                    }
                    if (!canReadOnTheseColumns.columns.includes(field)) {
                        throw new NotAuthorizedException(`You do not have permissions to query on - ${field}. You need any one of these permissions: ${PermissionHelper.getPermissionTitles(model.getColumnAccessControlFor(field)
                            ? model.getColumnAccessControlFor(field).read
                            : []).join(", ")}`);
                    }
                }
                continue;
            }
            if (!canReadOnTheseColumns.columns.includes(key)) {
                if (!tableColumns.includes(key)) {
                    throw new BadDataException(`Invalid column on ${model.singularName} - ${key}. Column does not exist.`);
                }
                throw new NotAuthorizedException(`You do not have permissions to query on - ${key}. You need any one of these permissions: ${PermissionHelper.getPermissionTitles(model.getColumnAccessControlFor(key)
                    ? model.getColumnAccessControlFor(key).read
                    : []).join(", ")}`);
            }
        }
    }
}
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object, Object]),
    __metadata("design:returntype", void 0)
], QueryPermission, "checkRelationQueryPermission", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object, Object]),
    __metadata("design:returntype", void 0)
], QueryPermission, "checkQueryPermission", null);
//# sourceMappingURL=QueryPermission.js.map