# -*- 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 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): setup_jwt(config) repo = get_cw_repo(config) repo.api_transactions = ApiTransactionsRepository(repo) config.include(add_cw_routes, route_prefix=API_ROUTE_PREFIX)