Skip to content
Snippets Groups Projects
routes.py 4.97 KiB
Newer Older
# -*- coding: utf-8 -*-
# copyright 2022 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact https://www.logilab.fr -- mailto:contact@logilab.fr
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 2.1 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from typing import Union
from cubicweb.pyramid.core import CubicWebPyramidRequest
from cubicweb.schema_exporters import JSONSchemaExporter
from cubicweb.server.repository import Repository
from pyramid.config import Configurator
from pyramid.request import Request
from pyramid.view import view_config
from pyramid.httpexceptions import HTTPBadRequest, HTTPForbidden, HTTPNotFound
Frank Bessou's avatar
Frank Bessou committed
from cubicweb_api.api_transaction import ApiTransactionsRepository
from cubicweb_api.jwt_auth import setup_jwt
API_PATTERN_PREFIX = "v1_"
API_ROUTE_PREFIX = "/api/v1/"
DEFAULT_ROUTE_PARAMS = {
    "request_method": "POST",
    "renderer": "json",
    "require_csrf": False,
def get_cw_request(request: Request) -> CubicWebPyramidRequest:
    return request.cw_request


def get_cw_repo(req_or_conf: Union[Request, Configurator]) -> Repository:
    return req_or_conf.registry["cubicweb.repository"]


def cw_view_config(route_name: str, **kwargs):
    return view_config(
        route_name=f"{API_PATTERN_PREFIX}{route_name}",
        **dict(DEFAULT_ROUTE_PARAMS, **kwargs),
    )


@cw_view_config(route_name="schema", request_method="GET")
def schema_route(request: Request):
    repo = get_cw_repo(request)
    exporter = JSONSchemaExporter()
    return exporter.export_as_dict(repo.schema)


@cw_view_config(route_name="rql")
def rql_route(request: Request):
    query = request.json["query"]
    params = request.json["params"]
    if not query:
        error = HTTPBadRequest()
        error.explanation = "No query provided."
        raise error
    result = get_cw_request(request).execute(query, params)
    return result.rows


@cw_view_config(route_name="login")
def login_route(request: Request):
    login = request.json_body["login"]
    pwd = request.json_body["password"]

    repo = get_cw_repo(request)
    with repo.internal_cnx() as cnx:
        cwuser = repo.authenticate_user(cnx, login, password=pwd)

    request.authentication_policy.remember(
        request,
        cwuser.eid,
        login=cwuser.login,
        firstname=cwuser.firstname,
        lastname=cwuser.surname,
    )
    request.response.status_code = 204
@cw_view_config(route_name="transaction")
def transaction_route(request: Request):
    transactions = get_cw_repo(request).api_transactions
    action = request.json["action"]
    if action == "begin":
        return transaction_begin(request, transactions)
    elif action == "execute":
        return transaction_execute(request, transactions)
    elif action == "commit":
        return transaction_commit(request, transactions)
    elif action == "rollback":
        return transaction_rollback(request, transactions)


def transaction_begin(request: Request, transactions: ApiTransactionsRepository) -> str:
    user = get_cw_request(request).user
    return transactions.begin_transaction(user)


def transaction_execute(request: Request, transactions: ApiTransactionsRepository):
    uuid = request.json["uuid"]
    rql = request.json["query"]
    params = request.json["params"]
    result = transactions[uuid].execute(rql, params)
    return result.rows


def transaction_commit(
    request: Request, transactions: ApiTransactionsRepository
) -> None:
    uuid = request.json["uuid"]
    commit_result = transactions[uuid].commit()
    transactions[uuid].rollback()
    return commit_result


def transaction_rollback(
    request: Request, transactions: ApiTransactionsRepository
) -> None:
    uuid = request.json["uuid"]
    rollback_result = transactions[uuid].rollback()
    transactions.end_transaction(uuid)
    return rollback_result


@cw_view_config(route_name="help", request_method="GET")
def help_route(_request: Request):
    """TO IMPLEMENT"""
    return


def add_route(config: Configurator, name: str):
    config.add_route(f"{API_PATTERN_PREFIX}{name}", f"/{name}")


def add_cw_routes(config: Configurator):
    add_route(config, "schema")
    add_route(config, "rql")
    add_route(config, "login")
    add_route(config, "transaction")
    add_route(config, "help")
    config.scan()
def includeme(config: Configurator):
    repo = get_cw_repo(config)
Frank Bessou's avatar
Frank Bessou committed
    repo.api_transactions = ApiTransactionsRepository(repo)
    config.include(add_cw_routes, route_prefix=API_ROUTE_PREFIX)