<commit_before>// Start using koa2 as normal

import Application from 'koa';
import Router from 'koa-router';
import logger from 'koa-logger';
import bodyParser from 'koa-bodyparser';
import cors from 'kcors';
import queryString from 'query-string';
import {Authentication} from './auth';
import {Neo4jConnection, Procedure, API} from './data';
import {haveIntersection, readMissingFromDefault} from './util';

const defaultOptions = {
    apis: [],
    log: true,
    neo4j: {
        boltUrl: 'bolt://localhost',
        user: 'neo4j',
        password: '<PASSWORD>'
    }
};


class KoaNeo4jApp extends Application {
    constructor(options) {
        super();
        options = readMissingFromDefault(options, defaultOptions);

        this.router = new Router();
        this.configuredAuthentication = false;
        this.configuredCors = false;

        this.methods = {
            'POST': this.router.post,
            'GET': this.router.get,
            'DEL': this.router.del
        };

        if (options.log)
            this.use(logger());

        this.neo4jConnection = new Neo4jConnection(options.neo4j);
        this.neo4jInitialized = this.neo4jConnection.initialized;


        if (options.authentication)
            this.configureAuthentication(options.authentication);

        if (!this.configuredCors)
            this.configureCors(options.cors);

        this
            .use(async (ctx, next) => {
                try {
                    await next();
                } catch (error) {
                    ctx.body = { error: String(error) };
                    ctx.status = error.status;
                }
            })
            .use(bodyParser({
                onerror(err, ctx) {
                    ctx.throw('Cannot parse request body', 400);
                }
            }))
            .use(this.router.routes());

        this.executeCypher = this.neo4jConnection.executeCypher;

        for (const api of options.apis)
            this.defineAPI(api);
    }

    defineAPI(options) {
        const api = new API(this.neo4jConnection, options);
        const handler = async(ctx, next) => {
            try {
                if (api.requiresJwtAuthentication)
                    try {
                        await this.authentication.authenticateJwt(ctx, next);
                    } catch (error) {
                        // No Authorization header
                        ctx.status = 401;
                        ctx.body = {error: 'Error: Authorization required'};
                        return;
                    }

                if (api.requiresJwtAuthentication &&
                    !haveIntersection(ctx.user.roles, api.allowedRoles)) {
                    // Incorrect roles
                    ctx.status = 403;
                    ctx.body = {error: "Error: You don't have permission for this"};
                    return;
                }

                let params = {};
                if (ctx.url.indexOf('?') >= 0) {
                    params = `?${ctx.url.split('?')[1]}`;
                    params = queryString.parse(params);
                }
                params = {...params, ...ctx.params, ...ctx.request.body};
                try {
                    ctx.body = await api.response(params, ctx.user);
                } catch (error) {
                    ctx.status = 409;
                    ctx.body = {error: error.fields ? JSON.stringify(error.fields[0])
                        : String(error)};
                }
            } catch (error) {
                ctx.status = 400;
                ctx.body = String(error);
            }
        };
        this.methods[api.method].apply(this.router, [api.route, handler]);
        return api;
    }

    configureAuthentication(options) {
        if (this.configuredAuthentication)
            throw new Error('Authentication already configured');
        this.authentication = new Authentication(this.neo4jConnection, options);
        this.use(this.authentication.passport.initialize());
        this.router.post(options.route, this.authentication.authenticateLocal);
        this.configuredAuthentication = true;
    }


    configureCors(options) {
        if (this.configuredCors)
            throw new Error('KCors already configured');
        this.use(cors(options));
        this.configuredCors = true;
    }

    createProcedure(options) {
        return (new Procedure(this.neo4jConnection, options)).response;<commit_msg>added await in api handler<commit_after>// Start using koa2 as normal

import Application from 'koa';
import Router from 'koa-router';
import logger from 'koa-logger';
import bodyParser from 'koa-bodyparser';
import cors from 'kcors';
import queryString from 'query-string';
import {Authentication} from './auth';
import {Neo4jConnection, Procedure, API} from './data';
import {haveIntersection, readMissingFromDefault} from './util';

const defaultOptions = {
    apis: [],
    log: true,
    neo4j: {
        boltUrl: 'bolt://localhost',
        user: 'neo4j',
        password: '<PASSWORD>'
    }
};


class KoaNeo4jApp extends Application {
    constructor(options) {
        super();
        options = readMissingFromDefault(options, defaultOptions);

        this.router = new Router();
        this.configuredAuthentication = false;
        this.configuredCors = false;

        this.methods = {
            'POST': this.router.post,
            'GET': this.router.get,
            'DEL': this.router.del
        };

        if (options.log)
            this.use(logger());

        this.neo4jConnection = new Neo4jConnection(options.neo4j);
        this.neo4jInitialized = this.neo4jConnection.initialized;


        if (options.authentication)
            this.configureAuthentication(options.authentication);

        if (!this.configuredCors)
            this.configureCors(options.cors);

        this
            .use(async (ctx, next) => {
                try {
                    await next();
                } catch (error) {
                    ctx.body = { error: String(error) };
                    ctx.status = error.status;
                }
            })
            .use(bodyParser({
                onerror(err, ctx) {
                    ctx.throw('Cannot parse request body', 400);
                }
            }))
            .use(this.router.routes());

        this.executeCypher = this.neo4jConnection.executeCypher;

        for (const api of options.apis)
            this.defineAPI(api);
    }

    defineAPI(options) {
        const api = new API(this.neo4jConnection, options);
        const handler = async(ctx, next) => {
            try {
                if (api.requiresJwtAuthentication)
                    try {
                        await this.authentication.authenticateJwt(ctx, next);
                    } catch (error) {
                        // No Authorization header
                        ctx.status = 401;
                        ctx.body = {error: 'Error: Authorization required'};
                        return;
                    }

                if (api.requiresJwtAuthentication &&
                    !haveIntersection(ctx.user.roles, api.allowedRoles)) {
                    // Incorrect roles
                    ctx.status = 403;
                    ctx.body = {error: "Error: You don't have permission for this"};
                    return;
                }

                let params = {};
                if (ctx.url.indexOf('?') >= 0) {
                    params = `?${ctx.url.split('?')[1]}`;
                    params = queryString.parse(params);
                }
                params = {...params, ...ctx.params, ...ctx.request.body};
                try {
                    ctx.body = await api.response(params, ctx.user);
                } catch (error) {
                    ctx.status = 409;
                    ctx.body = {error: error.fields ? JSON.stringify(error.fields[0])
                        : String(error)};
                }
            } catch (error) {
                ctx.status = 400;
                ctx.body = String(error);
            }
            await next();
        };
        this.methods[api.method].apply(this.router, [api.route, handler]);
        return api;
    }

    configureAuthentication(options) {
        if (this.configuredAuthentication)
            throw new Error('Authentication already configured');
        this.authentication = new Authentication(this.neo4jConnection, options);
        this.use(this.authentication.passport.initialize());
        this.router.post(options.route, this.authentication.authenticateLocal);
        this.configuredAuthentication = true;
    }


    configureCors(options) {
        if (this.configuredCors)
            throw new Error('KCors already configured');
        this.use(cors(options));
        this.configuredCors = true;
    }

    createProcedure(options) {
        return (new Procedure(this.neo4jConnection, options)).response;
{'fraction_non_alphanumeric': 0.11247079764156191, 'fraction_numerical': 0.007119813104905996, 'mean_word_length': 1.5796269727403156, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 11, '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': '2700975', 'n_tokens_mistral': 2442, 'n_tokens_neox': 2275, 'n_words': 493}