<commit_before>import {Injectable} from "@angular/core";
import {M} from "../m";
import {IdaiFieldDocument} from "../model/idai-field-document";
import {Utils, ProjectConfiguration, ConfigLoader} from "../../node_modules/idai-components-2/idai-components-2";

/**
 * @author <NAME>
 * @author <NAME>
 */
@Injectable()
export class ValidationInterceptor {

    private projectConfiguration: ProjectConfiguration;

    constructor(private configLoader: ConfigLoader) {
        this.configLoader.projectConfiguration().subscribe((projectConfiguration) => {
            this.projectConfiguration = projectConfiguration;
        });
    }

    /**
     * @param doc
     * @returns {string} the error as key of m, <code>undefined</code> if no errors.
     */
    public validate(doc: IdaiFieldDocument): string {

        var resource = doc['resource'];

        if (!this.validateIdentifier(resource)) {
            return M.OBJLIST_IDMISSING;
        }

        if (resource['@id']) {
            if (!this.validateType(resource)) {
                return M.VALIDATION_ERROR_INVALIDTYPE;
            }

            if (!this.validateFields(resource)) {
                return M.VALIDATION_ERROR_INVALIDFIELD;
            }
        }
        
        return undefined;
    }

    /**
     * 
     * @param resource
     * @returns {boolean} true if the identifier of the resource is valid, otherwise false
     */
    private validateIdentifier(resource: any): boolean {
        
        return resource.identifier && resource.identifier.length > 0;
    }

    /**
     * 
     * @param resource
     * @returns {boolean} true if the type of the resource is valid, otherwise false
     */
    private validateType(resource: any): boolean {

        var type = Utils.getTypeFromId(resource['@id']);

        return this.projectConfiguration.getTypes().indexOf(type) > -1;
    }

    /**
     * 
     * @param resource
     * @returns {boolean} true if all fields of the resource are valid, otherwise false
     */
    private validateFields(resource: any): boolean {

        var fields = this.projectConfiguration.getFields(Utils.getTypeFromId(resource['@id']));
        var defaultFields = [ "@id", "type" ];

        for (var resourceField in resource) {
            if (resource.hasOwnProperty(resourceField)) {
                var fieldFound = false;
                for (var i in fields) {
                    if (fields[i].field == resourceField) {
                        fieldFound = true;
                        break;
                    }
                }
                if (!fieldFound && defaultFields.indexOf(resourceField) == -1) {
                    return false;
                }
            }
        }
        
        return true;
    }<commit_msg>allow relation fields during validation<commit_after>import {Injectable} from "@angular/core";
import {M} from "../m";
import {IdaiFieldDocument} from "../model/idai-field-document";
import {Utils, ConfigLoader} from "../../node_modules/idai-components-2/idai-components-2";
import {ProjectConfiguration, RelationsConfiguration} from "../../node_modules/idai-components-2/idai-components-2";

/**
 * @author <NAME>
 * @author <NAME>
 */
@Injectable()
export class ValidationInterceptor {

    private projectConfiguration: ProjectConfiguration;
    private relationsConfiguration: RelationsConfiguration;

    constructor(private configLoader: ConfigLoader) {
        this.configLoader.projectConfiguration().subscribe((projectConfiguration) => {
            this.projectConfiguration = projectConfiguration;
        });

        this.configLoader.relationsConfiguration().subscribe((relationsConfiguration) => {
            this.relationsConfiguration = relationsConfiguration;
        });
    }

    /**
     * @param doc
     * @returns {string} the error as key of m, <code>undefined</code> if no errors.
     */
    public validate(doc: IdaiFieldDocument): string {

        var resource = doc['resource'];

        if (!this.validateIdentifier(resource)) {
            return M.OBJLIST_IDMISSING;
        }

        if (resource['@id']) {
            if (!this.validateType(resource)) {
                return M.VALIDATION_ERROR_INVALIDTYPE;
            }

            if (!this.validateFields(resource)) {
                return M.VALIDATION_ERROR_INVALIDFIELD;
            }
        }
        
        return undefined;
    }

    /**
     * 
     * @param resource
     * @returns {boolean} true if the identifier of the resource is valid, otherwise false
     */
    private validateIdentifier(resource: any): boolean {
        
        return resource.identifier && resource.identifier.length > 0;
    }

    /**
     * 
     * @param resource
     * @returns {boolean} true if the type of the resource is valid, otherwise false
     */
    private validateType(resource: any): boolean {

        var type = Utils.getTypeFromId(resource['@id']);

        return this.projectConfiguration.getTypes().indexOf(type) > -1;
    }

    /**
     * 
     * @param resource
     * @returns {boolean} true if all fields of the resource are valid, otherwise false
     */
    private validateFields(resource: any): boolean {

        var projectFields = this.projectConfiguration.getFields(Utils.getTypeFromId(resource['@id']));
        var relationFields = this.relationsConfiguration.getRelationFields();
        var defaultFields = [ { field: "@id" }, { field: "type" } ];

        var fields = projectFields.concat(relationFields).concat(defaultFields);

        for (var resourceField in resource) {
            if (resource.hasOwnProperty(resourceField)) {
                var fieldFound = false;
                for (var i in fields) {
                    if (fields[i].field == resourceField) {
                        fieldFound = true;
                        break;
                    }
                }
                if (!fieldFound) {
                    return false;
                }
            }
        }
        
        return true;
    }
{'fraction_non_alphanumeric': 0.11107427055702918, 'fraction_numerical': 0.001823607427055703, 'mean_word_length': 2.0827797649463466, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3383936', 'n_tokens_mistral': 1547, 'n_tokens_neox': 1488, 'n_words': 370}