From 04b11d54b63483ffee2df0364010d128a0732095 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Mon, 31 Mar 2025 17:59:42 +0200 Subject: [PATCH 01/22] [ADD] cross_connect_server --- cross_connect_server/README.rst | 110 +++++ cross_connect_server/__init__.py | 1 + cross_connect_server/__manifest__.py | 25 + cross_connect_server/dependencies.py | 9 + cross_connect_server/models/__init__.py | 3 + .../models/cross_connect_client.py | 118 +++++ .../models/fastapi_endpoint.py | 104 ++++ cross_connect_server/models/res_users.py | 19 + cross_connect_server/readme/CONTRIBUTORS.md | 1 + cross_connect_server/readme/DESCRIPTION.md | 2 + cross_connect_server/readme/USAGE.md | 17 + cross_connect_server/routers/__init__.py | 1 + cross_connect_server/routers/cross_connect.py | 78 +++ cross_connect_server/schemas.py | 47 ++ .../security/ir_model_access.xml | 17 + cross_connect_server/security/res_groups.xml | 15 + .../static/description/index.html | 448 ++++++++++++++++++ cross_connect_server/tests/__init__.py | 1 + .../tests/test_cross_connect_server.py | 373 +++++++++++++++ .../views/fastapi_endpoint_views.xml | 46 ++ 20 files changed, 1435 insertions(+) create mode 100644 cross_connect_server/README.rst create mode 100644 cross_connect_server/__init__.py create mode 100644 cross_connect_server/__manifest__.py create mode 100644 cross_connect_server/dependencies.py create mode 100644 cross_connect_server/models/__init__.py create mode 100644 cross_connect_server/models/cross_connect_client.py create mode 100644 cross_connect_server/models/fastapi_endpoint.py create mode 100644 cross_connect_server/models/res_users.py create mode 100644 cross_connect_server/readme/CONTRIBUTORS.md create mode 100644 cross_connect_server/readme/DESCRIPTION.md create mode 100644 cross_connect_server/readme/USAGE.md create mode 100644 cross_connect_server/routers/__init__.py create mode 100644 cross_connect_server/routers/cross_connect.py create mode 100644 cross_connect_server/schemas.py create mode 100644 cross_connect_server/security/ir_model_access.xml create mode 100644 cross_connect_server/security/res_groups.xml create mode 100644 cross_connect_server/static/description/index.html create mode 100644 cross_connect_server/tests/__init__.py create mode 100644 cross_connect_server/tests/test_cross_connect_server.py create mode 100644 cross_connect_server/views/fastapi_endpoint_views.xml diff --git a/cross_connect_server/README.rst b/cross_connect_server/README.rst new file mode 100644 index 0000000000..c274ff7a11 --- /dev/null +++ b/cross_connect_server/README.rst @@ -0,0 +1,110 @@ +==================== +Cross Connect Server +==================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:e7f2983ebb91caf2611da85b500923b3a91de86fbb4577c967a2a30e0ce7e739 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--auth-lightgray.png?logo=github + :target: https://github.com/OCA/server-auth/tree/16.0/cross_connect_server + :alt: OCA/server-auth +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/server-auth-16-0/server-auth-16-0-cross_connect_server + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/server-auth&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows other odoo instances, where the +``cross_connect_client`` module is installed and configured, users to +connect directly on this odoo instance. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +First of all after installing the module, you need to configure a +fastapi endpoint. + +In order to do that, you need to go to the menu +``FastAPI > FastAPI Endpoints`` and create a new endpoint for the client +to connect to. + +Fill the fields with the endpoint's information : + +- App: ``cross_connect`` +- Cross Connect Allowed Groups: The groups that will be allowed to be + selected for the clients groups. + +Then for each client, you will have to add an entry in the +``Cross Connect Clients`` table. + +An api key will be automatically generated for each client, this is the +key that you will have to provide to the client in order for them to +connect to the server. You will also have to choose the groups that this +client will be able to give to its users. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Akretion + +Contributors +------------ + +- Florian Mounier florian.mounier@akretion.com + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-paradoxxxzero| image:: https://github.com/paradoxxxzero.png?size=40px + :target: https://github.com/paradoxxxzero + :alt: paradoxxxzero + +Current `maintainer `__: + +|maintainer-paradoxxxzero| + +This module is part of the `OCA/server-auth `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/cross_connect_server/__init__.py b/cross_connect_server/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/cross_connect_server/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/cross_connect_server/__manifest__.py b/cross_connect_server/__manifest__.py new file mode 100644 index 0000000000..57e066de65 --- /dev/null +++ b/cross_connect_server/__manifest__.py @@ -0,0 +1,25 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Cross Connect Server", + "version": "16.0.1.0.0", + "author": "Akretion, Odoo Community Association (OCA)", + "summary": "Cross Connect Server allows Cross Connect Client to connect to it.", + "category": "Tools", + "depends": ["extendable_fastapi", "server_environment"], + "website": "https://github.com/OCA/server-auth", + "data": [ + "security/res_groups.xml", + "security/ir_model_access.xml", + "views/fastapi_endpoint_views.xml", + ], + "maintainers": ["paradoxxxzero"], + "demo": [], + "installable": True, + "license": "AGPL-3", + "external_dependencies": { + "python": ["pyjwt"], + }, +} diff --git a/cross_connect_server/dependencies.py b/cross_connect_server/dependencies.py new file mode 100644 index 0000000000..6f2ce7c3af --- /dev/null +++ b/cross_connect_server/dependencies.py @@ -0,0 +1,9 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from .models.cross_connect_client import CrossConnectClient + + +def authenticated_cross_connect_client() -> CrossConnectClient: + pass diff --git a/cross_connect_server/models/__init__.py b/cross_connect_server/models/__init__.py new file mode 100644 index 0000000000..108ba9f5c2 --- /dev/null +++ b/cross_connect_server/models/__init__.py @@ -0,0 +1,3 @@ +from . import cross_connect_client +from . import fastapi_endpoint +from . import res_users diff --git a/cross_connect_server/models/cross_connect_client.py b/cross_connect_server/models/cross_connect_client.py new file mode 100644 index 0000000000..04f5f0ed9a --- /dev/null +++ b/cross_connect_server/models/cross_connect_client.py @@ -0,0 +1,118 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from datetime import datetime, timedelta, timezone +from secrets import token_urlsafe + +import jwt + +from odoo import _, api, fields, models +from odoo.exceptions import AccessDenied + + +class CrossConnectClient(models.Model): + _name = "cross.connect.client" + _description = "Cross Connect Client" + _inherit = "server.env.mixin" + + name = fields.Char(required=True) + + endpoint_id = fields.Many2one( + "fastapi.endpoint", + required=True, + string="Endpoint", + ) + + api_key = fields.Char( + required=True, + string="API Key", + help="The API key to give to configure on the client.", + default=lambda self: self._generate_api_key(), + ) + + allowed_group_ids = fields.Many2many( + related="endpoint_id.cross_connect_allowed_group_ids", + ) + + group_ids = fields.Many2many( + "res.groups", + string="Groups", + help="The groups that this client belongs to.", + domain="[('id', 'in', allowed_group_ids)]", + ) + + user_ids = fields.One2many( + "res.users", + "cross_connect_client_id", + string="Users", + help="The users created by this cross connection.", + ) + user_count = fields.Integer( + compute="_compute_user_count", + string="Cross Connected User Count", + help="The number of users created by this cross connection.", + ) + + @api.model + def _generate_api_key(self): + # generate random ~64 chars secret key + return token_urlsafe(64) + + @api.depends("user_ids") + def _compute_user_count(self): + for record in self: + record.user_count = len(record.user_ids) + + def _request_access(self, access_request): + # check groups + groups = self.env["res.groups"].browse(access_request.groups) + if groups - self.group_ids or not groups.exists(): + raise AccessDenied(_("You are not allowed to access this endpoint.")) + + user = self.user_ids.filtered( + lambda u: u.cross_connect_client_user_id == access_request.id + ) + vals = { + "login": access_request.login, + "email": access_request.email, + "name": access_request.name, + "lang": access_request.lang, + "groups_id": [(6, 0, groups.ids)], + "cross_connect_client_id": self.id, + "cross_connect_client_user_id": access_request.id, + } + # Create user if not exists + if not user: + user = self.env["res.users"].create(vals) + else: + user.write(vals) + + return jwt.encode( + { + "exp": datetime.now(tz=timezone.utc) + timedelta(minutes=2), + "aud": str(self.id), + "id": user.id, + "redirect_url": access_request.redirect_url or "/web", + }, + self.endpoint_id.cross_connect_secret_key, + algorithm="HS256", + ) + + def _log_from_token(self, token): + try: + obj = jwt.decode( + token, + self.endpoint_id.cross_connect_secret_key, + audience=str(self.id), + options={"require": ["exp", "aud", "id"]}, + algorithms=["HS256"], + ) + except jwt.PyJWTError as e: + raise AccessDenied(_("Invalid Token")) from e + + user = self.env["res.users"].browse(obj["id"]) + + if not user: + raise AccessDenied(_("Invalid Token")) + + return user, obj["redirect_url"] diff --git a/cross_connect_server/models/fastapi_endpoint.py b/cross_connect_server/models/fastapi_endpoint.py new file mode 100644 index 0000000000..774e485346 --- /dev/null +++ b/cross_connect_server/models/fastapi_endpoint.py @@ -0,0 +1,104 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from secrets import token_urlsafe +from typing import Annotated, Callable, Dict, List + +from fastapi import APIRouter, Depends, HTTPException, status +from fastapi.security import APIKeyHeader + +from odoo import api, fields, models +from odoo.api import Environment + +from odoo.addons.fastapi.dependencies import fastapi_endpoint, odoo_env + +from ..dependencies import authenticated_cross_connect_client +from ..routers import cross_connect_router +from .cross_connect_client import CrossConnectClient + + +class FastapiEndpoint(models.Model): + _inherit = "fastapi.endpoint" + + app = fields.Selection( + selection_add=[("cross_connect", "Cross Connect Endpoint")], + ondelete={"cross_connect": "cascade"}, + ) + + cross_connect_client_ids = fields.One2many( + "cross.connect.client", + "endpoint_id", + string="Cross Connect Clients", + help="The clients that can access this endpoint.", + ) + cross_connect_allowed_group_ids = fields.Many2many( + "res.groups", + string="Cross Connect Allowed Groups", + help="The groups that can access the cross connect clients of this endpoint.", + ) + cross_connect_secret_key = fields.Char( + help="The secret key used for cross connection.", + required=True, + default=lambda self: self._generate_secret_key(), + ) + + @api.model + def _generate_secret_key(self): + # generate random ~64 chars secret key + return token_urlsafe(64) + + def _get_fastapi_routers(self) -> List[APIRouter]: + routers = super()._get_fastapi_routers() + + if self.app == "cross_connect": + routers += [cross_connect_router] + + return routers + + def _get_app_dependencies_overrides(self) -> Dict[Callable, Callable]: + overrides = super()._get_app_dependencies_overrides() + + if self.app == "cross_connect": + overrides[ + authenticated_cross_connect_client + ] = api_key_based_authenticated_cross_connect_client + + return overrides + + def _get_routing_info(self): + if self.app == "cross_connect": + # Force to not save the HTTP session for the login to work correctly + self.save_http_session = False + return super()._get_routing_info() + + @property + def _server_env_fields(self): + return {"cross_connect_secret_key": {}} + + +def api_key_based_authenticated_cross_connect_client( + api_key: Annotated[ + str, + Depends( + APIKeyHeader( + name="api-key", + description="Cross Connect Client API key.", + ) + ), + ], + fastapi_endpoint: Annotated[FastapiEndpoint, Depends(fastapi_endpoint)], + env: Annotated[Environment, Depends(odoo_env)], +) -> CrossConnectClient: + cross_connect_client = ( + env["cross.connect.client"] + .sudo() + .search( + [("api_key", "=", api_key), ("endpoint_id", "=", fastapi_endpoint.id)], + limit=1, + ) + ) + if not cross_connect_client: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect API Key" + ) + return cross_connect_client diff --git a/cross_connect_server/models/res_users.py b/cross_connect_server/models/res_users.py new file mode 100644 index 0000000000..d98d7ef9c5 --- /dev/null +++ b/cross_connect_server/models/res_users.py @@ -0,0 +1,19 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResUsers(models.Model): + _inherit = "res.users" + + cross_connect_client_id = fields.Many2one( + "cross.connect.client", + string="Cross Connect Client", + help="The cross connect client that created this user.", + ) + cross_connect_client_user_id = fields.Integer( + string="Cross Connect Client User ID", + help="The user ID on the cross connect client.", + ) diff --git a/cross_connect_server/readme/CONTRIBUTORS.md b/cross_connect_server/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..328a37da87 --- /dev/null +++ b/cross_connect_server/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Florian Mounier diff --git a/cross_connect_server/readme/DESCRIPTION.md b/cross_connect_server/readme/DESCRIPTION.md new file mode 100644 index 0000000000..4a034abe18 --- /dev/null +++ b/cross_connect_server/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ +This module allows other odoo instances, where the `cross_connect_client` module is +installed and configured, users to connect directly on this odoo instance. diff --git a/cross_connect_server/readme/USAGE.md b/cross_connect_server/readme/USAGE.md new file mode 100644 index 0000000000..6d6e80bd57 --- /dev/null +++ b/cross_connect_server/readme/USAGE.md @@ -0,0 +1,17 @@ +First of all after installing the module, you need to configure a fastapi endpoint. + +In order to do that, you need to go to the menu `FastAPI > FastAPI Endpoints` and create +a new endpoint for the client to connect to. + +Fill the fields with the endpoint's information : + +- App: `cross_connect` +- Cross Connect Allowed Groups: The groups that will be allowed to be selected for the + clients groups. + +Then for each client, you will have to add an entry in the `Cross Connect Clients` +table. + +An api key will be automatically generated for each client, this is the key that you +will have to provide to the client in order for them to connect to the server. You will +also have to choose the groups that this client will be able to give to its users. diff --git a/cross_connect_server/routers/__init__.py b/cross_connect_server/routers/__init__.py new file mode 100644 index 0000000000..114cbd2c8b --- /dev/null +++ b/cross_connect_server/routers/__init__.py @@ -0,0 +1 @@ +from .cross_connect import cross_connect_router diff --git a/cross_connect_server/routers/cross_connect.py b/cross_connect_server/routers/cross_connect.py new file mode 100644 index 0000000000..94fe4ee83c --- /dev/null +++ b/cross_connect_server/routers/cross_connect.py @@ -0,0 +1,78 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from typing import Annotated + +from fastapi import APIRouter, Depends +from fastapi.responses import RedirectResponse + +from odoo import _, api +from odoo.exceptions import MissingError +from odoo.http import SESSION_LIFETIME, root + +from odoo.addons.fastapi.dependencies import odoo_env + +from ..dependencies import authenticated_cross_connect_client +from ..models.cross_connect_client import CrossConnectClient +from ..schemas import AccessRequest, AccessResponse, SyncResponse + +cross_connect_router = APIRouter(tags=["Cross Connect"]) + + +@cross_connect_router.get("/cross_connect/sync") +async def sync( + cross_connect_client: Annotated[ + CrossConnectClient, Depends(authenticated_cross_connect_client) + ], +) -> SyncResponse: + """Send back to client sync information.""" + return SyncResponse.from_groups(cross_connect_client.group_ids) + + +@cross_connect_router.post("/cross_connect/access") +async def access( + cross_connect_client: Annotated[ + CrossConnectClient, Depends(authenticated_cross_connect_client) + ], + access_request: AccessRequest, +) -> AccessResponse: + """Send back to client a token.""" + return AccessResponse.from_params( + client_id=cross_connect_client.id, + token=cross_connect_client.sudo()._request_access(access_request), + ) + + +@cross_connect_router.get("/cross_connect/login/{client_id}/{token}") +async def login( + client_id: int, + token: str, + env: Annotated[api.Environment, Depends(odoo_env)], +) -> RedirectResponse: + """Log user and redirect to odoo index.""" + cross_connect_client = env["cross.connect.client"].sudo().browse(client_id) + if not cross_connect_client: + raise MissingError(_("Client not found")) + user, redirect_url = cross_connect_client.sudo()._log_from_token(token) + user = user.with_user(user) + user._update_last_login() + env = env(user=user.id) + + # Create a odoo session + session = root.session_store.new() + session.db = env.cr.dbname + session.uid = user.id + session.login = user.login + session.context = dict(env["res.users"].context_get()) + session.session_token = user._compute_session_token(session.sid) + root.session_store.save(session) + # Redirect after login + response = RedirectResponse(url=redirect_url) + response.set_cookie( + "session_id", + session.sid, + httponly=True, + max_age=SESSION_LIFETIME, + ) + return response diff --git a/cross_connect_server/schemas.py b/cross_connect_server/schemas.py new file mode 100644 index 0000000000..04e59628f7 --- /dev/null +++ b/cross_connect_server/schemas.py @@ -0,0 +1,47 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from extendable_pydantic import StrictExtendableBaseModel + + +class CrossConnectGroup(StrictExtendableBaseModel): + id: int + name: str + comment: str | None = None + + @classmethod + def from_group(cls, group): + return cls.model_construct( + id=group.id, + name=group.full_name, + comment=group.comment or None, + ) + + +class SyncResponse(StrictExtendableBaseModel): + groups: list[CrossConnectGroup] + + @classmethod + def from_groups(cls, groups): + return cls.model_construct( + groups=[CrossConnectGroup.from_group(group) for group in groups] + ) + + +class AccessRequest(StrictExtendableBaseModel, extra="ignore"): + id: int + name: str + login: str + email: str + lang: str + groups: list[int] + redirect_url: str = None + + +class AccessResponse(StrictExtendableBaseModel): + client_id: int + token: str + + @classmethod + def from_params(cls, token, client_id): + return cls.model_construct(token=token, client_id=client_id) diff --git a/cross_connect_server/security/ir_model_access.xml b/cross_connect_server/security/ir_model_access.xml new file mode 100644 index 0000000000..cac56e1398 --- /dev/null +++ b/cross_connect_server/security/ir_model_access.xml @@ -0,0 +1,17 @@ + + + + + Cross Connect Client: Manager RW access + + + + + + + + diff --git a/cross_connect_server/security/res_groups.xml b/cross_connect_server/security/res_groups.xml new file mode 100644 index 0000000000..33defad930 --- /dev/null +++ b/cross_connect_server/security/res_groups.xml @@ -0,0 +1,15 @@ + + + + + Cross Connect Manager + + + diff --git a/cross_connect_server/static/description/index.html b/cross_connect_server/static/description/index.html new file mode 100644 index 0000000000..fed0bcb4ea --- /dev/null +++ b/cross_connect_server/static/description/index.html @@ -0,0 +1,448 @@ + + + + + +Cross Connect Server + + + +
+

Cross Connect Server

+ + +

Beta License: AGPL-3 OCA/server-auth Translate me on Weblate Try me on Runboat

+

This module allows other odoo instances, where the +cross_connect_client module is installed and configured, users to +connect directly on this odoo instance.

+

Table of contents

+ +
+

Usage

+

First of all after installing the module, you need to configure a +fastapi endpoint.

+

In order to do that, you need to go to the menu +FastAPI > FastAPI Endpoints and create a new endpoint for the client +to connect to.

+

Fill the fields with the endpoint’s information :

+
    +
  • App: cross_connect
  • +
  • Cross Connect Allowed Groups: The groups that will be allowed to be +selected for the clients groups.
  • +
+

Then for each client, you will have to add an entry in the +Cross Connect Clients table.

+

An api key will be automatically generated for each client, this is the +key that you will have to provide to the client in order for them to +connect to the server. You will also have to choose the groups that this +client will be able to give to its users.

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Akretion
  • +
+
+ +
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

paradoxxxzero

+

This module is part of the OCA/server-auth project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/cross_connect_server/tests/__init__.py b/cross_connect_server/tests/__init__.py new file mode 100644 index 0000000000..f49cef96d5 --- /dev/null +++ b/cross_connect_server/tests/__init__.py @@ -0,0 +1 @@ +from . import test_cross_connect_server diff --git a/cross_connect_server/tests/test_cross_connect_server.py b/cross_connect_server/tests/test_cross_connect_server.py new file mode 100644 index 0000000000..9006cf61a8 --- /dev/null +++ b/cross_connect_server/tests/test_cross_connect_server.py @@ -0,0 +1,373 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo.http import root +from odoo.tests.common import RecordCapturer, tagged + +from odoo.addons.extendable_fastapi.tests.common import FastAPITransactionCase + +from ..routers import cross_connect_router + + +@tagged("post_install", "-at_install") +class TestCrossConnectServer(FastAPITransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + + cls.endpoint = cls.env["fastapi.endpoint"].create( + { + "name": "Cross Connect Server Endpoint", + "root_path": "/api", + "app": "cross_connect", + } + ) + cls.available_groups = ( + cls.env.ref("base.group_user") + | cls.env.ref("fastapi.group_fastapi_user") + | cls.env.ref("fastapi.group_fastapi_manager") + ) + + cls.endpoint.cross_connect_allowed_group_ids = cls.available_groups + + cls.client = cls.env["cross.connect.client"].create( + { + "name": "Test Client", + "endpoint_id": cls.endpoint.id, + "api_key": "server-api-key", + "group_ids": [ + ( + 6, + 0, + ( + cls.available_groups + - cls.env.ref("fastapi.group_fastapi_manager") + ).ids, + ) + ], + } + ) + + cls.other_client = cls.env["cross.connect.client"].create( + { + "name": "Other Test Client", + "endpoint_id": cls.endpoint.id, + "api_key": "other-server-api-key", + "group_ids": [ + ( + 6, + 0, + (cls.available_groups - cls.env.ref("base.group_user")).ids, + ) + ], + } + ) + + cls.endpoint_user = cls.env["res.users"].create( + { + "name": "FastAPI Endpoint User", + "login": "fastapi_endpoint_user", + "groups_id": [ + (6, 0, [cls.env.ref("fastapi.group_fastapi_endpoint_runner").id]) + ], + } + ) + + cls.endpoint._handle_registry_sync(cls.endpoint.ids) + + cls.default_fastapi_running_user = cls.endpoint_user + cls.default_fastapi_router = cross_connect_router + cls.default_fastapi_app = cls.endpoint._get_app() + cls.default_fastapi_dependency_overrides = ( + cls.default_fastapi_app.dependency_overrides + ) + cls.default_fastapi_app.exception_handlers = {} + + def test_base(self): + self.assertTrue(self.endpoint.cross_connect_secret_key) + self.assertEqual(len(self.endpoint.cross_connect_client_ids), 2) + self.assertFalse(self.endpoint.save_http_session) + self.assertFalse(self.client.user_ids) + + def test_sync_ok(self): + with self._create_test_client() as test_client: + response = test_client.get( + "/cross_connect/sync", headers={"api-key": "server-api-key"} + ) + self.assertEqual(response.status_code, 200) + self.assertEqual( + response.json(), + { + "groups": [ + { + "id": self.env.ref("base.group_user").id, + "name": "User types / Internal User", + "comment": None, + }, + { + "id": self.env.ref("fastapi.group_fastapi_user").id, + "name": "FastAPI / User", + "comment": None, + }, + ] + }, + ) + + def test_sync_other(self): + with self._create_test_client() as test_client: + response = test_client.get( + "/cross_connect/sync", headers={"api-key": "other-server-api-key"} + ) + self.assertEqual(response.status_code, 200) + self.assertEqual( + response.json(), + { + "groups": [ + { + "id": self.env.ref("fastapi.group_fastapi_manager").id, + "name": "FastAPI / Administrator", + "comment": None, + }, + { + "id": self.env.ref("fastapi.group_fastapi_user").id, + "name": "FastAPI / User", + "comment": None, + }, + ] + }, + ) + + def test_sync_401(self): + with self._create_test_client(raise_server_exceptions=False) as test_client: + response = test_client.get( + "/cross_connect/sync", headers={"api-key": "wrong-api-key"} + ) + self.assertEqual(response.status_code, 401) + + def test_access_ok(self): + with RecordCapturer(self.env["res.users"], []) as rc: + with self._create_test_client() as test_client: + response = test_client.post( + "/cross_connect/access", + headers={"api-key": "server-api-key"}, + json={ + "id": 12, + "name": "Client User", + "login": "user@client.example.org", + "email": "user@client.example.org", + "lang": "en_US", + "groups": [ + self.env.ref("base.group_user").id, + ], + }, + ) + + self.assertEqual(response.status_code, 200) + json = response.json() + self.assertEqual(json["client_id"], self.client.id) + self.assertTrue(json["token"]) + + self.assertEqual(len(rc.records), 1) + new_user = rc.records[0] + self.assertEqual(new_user.name, "Client User") + self.assertEqual(new_user.login, "user@client.example.org") + self.assertEqual(new_user.email, "user@client.example.org") + self.assertEqual(new_user.lang, "en_US") + self.assertEqual(new_user.cross_connect_client_id.id, self.client.id) + self.assertEqual(new_user.cross_connect_client_user_id, 12) + self.assertIn( + self.env.ref("base.group_user"), + new_user.groups_id, + ) + self.assertNotIn(self.env.ref("fastapi.group_fastapi_user"), new_user.groups_id) + self.assertNotIn( + self.env.ref("fastapi.group_fastapi_manager"), new_user.groups_id + ) + + def test_access_401(self): + with RecordCapturer(self.env["res.users"], []) as rc: + with self._create_test_client(raise_server_exceptions=False) as test_client: + response = test_client.post( + "/cross_connect/access", + headers={"api-key": "wrong-api-key"}, + json={ + "id": 12, + "name": "Client User", + "login": "user@client.example.org", + "email": "user@client.example.org", + "lang": "en_US", + "groups": [ + self.env.ref("base.group_user").id, + ], + }, + ) + + self.assertEqual(response.status_code, 401) + self.assertEqual(len(rc.records), 0) + + def test_access_wrong_groups(self): + with RecordCapturer(self.env["res.users"], []) as rc: + with self._create_test_client(raise_server_exceptions=False) as test_client: + response = test_client.post( + "/cross_connect/access", + headers={"api-key": "wrong-api-key"}, + json={ + "id": 12, + "name": "Client User", + "login": "user@client.example.org", + "email": "user@client.example.org", + "lang": "en_US", + "groups": [ + self.env.ref("fastapi.group_fastapi_manager").id, + ], + }, + ) + + self.assertEqual(response.status_code, 401) + self.assertEqual(len(rc.records), 0) + + def test_access_existing(self): + with RecordCapturer(self.env["res.users"], []) as rc: + with self._create_test_client() as test_client: + response = test_client.post( + "/cross_connect/access", + headers={"api-key": "server-api-key"}, + json={ + "id": 12, + "name": "Client User", + "login": "user@client.example.org", + "email": "user@client.example.org", + "lang": "en_US", + "groups": [ + self.env.ref("base.group_user").id, + ], + }, + ) + self.assertEqual(response.status_code, 200) + + with RecordCapturer(self.env["res.users"], []) as rc2: + with self._create_test_client() as test_client: + response = test_client.post( + "/cross_connect/access", + headers={"api-key": "server-api-key"}, + json={ + "id": 12, + "name": "Client User2", + "login": "user2@client.example.org", + "email": "user2@client.example.org", + "lang": "en_US", + "groups": [ + self.env.ref("fastapi.group_fastapi_user").id, + ], + }, + ) + + self.assertEqual(response.status_code, 200) + json = response.json() + self.assertEqual(json["client_id"], self.client.id) + self.assertTrue(json["token"]) + + self.assertEqual(len(rc.records), 1) + self.assertEqual(len(rc2.records), 0) + new_user = rc.records[0] + self.assertEqual(new_user.name, "Client User2") + self.assertEqual(new_user.login, "user2@client.example.org") + self.assertEqual(new_user.email, "user2@client.example.org") + self.assertEqual(new_user.lang, "en_US") + self.assertIn(self.env.ref("fastapi.group_fastapi_user"), new_user.groups_id) + self.assertNotIn( + self.env.ref("fastapi.group_fastapi_manager"), new_user.groups_id + ) + + def test_login_ok(self): + with RecordCapturer(self.env["res.users"], []) as rc: + with self._create_test_client() as test_client: + response = test_client.post( + "/cross_connect/access", + headers={"api-key": "server-api-key"}, + json={ + "id": 12, + "name": "Client User", + "login": "user@client.example.org", + "email": "user@client.example.org", + "lang": "en_US", + "groups": [ + self.env.ref("base.group_user").id, + ], + }, + ) + self.assertEqual(response.status_code, 200) + + new_user = rc.records[0] + + json = response.json() + + with self._create_test_client() as test_client: + response = test_client.get( + f"/cross_connect/login/{json['client_id']}/{json['token']}", + follow_redirects=False, + ) + + self.assertEqual(response.status_code, 307) + self.assertEqual(response.headers["location"], "/web") + self.assertIn("session_id", response.cookies) + self.assertEqual( + root.session_store.get(response.cookies["session_id"]).get("uid"), + new_user.id, + ) + + def test_login_wrong_client(self): + with self._create_test_client() as test_client: + response = test_client.post( + "/cross_connect/access", + headers={"api-key": "server-api-key"}, + json={ + "id": 12, + "name": "Client User", + "login": "user@client.example.org", + "email": "user@client.example.org", + "lang": "en_US", + "groups": [ + self.env.ref("base.group_user").id, + ], + }, + ) + self.assertEqual(response.status_code, 200) + + json = response.json() + + with self._create_test_client(raise_server_exceptions=False) as test_client: + response = test_client.get( + f"/cross_connect/login/{self.other_client.id}/{json['token']}", + follow_redirects=False, + ) + + self.assertEqual(response.status_code, 403) + + def test_login_wrong_token(self): + with self._create_test_client() as test_client: + response = test_client.post( + "/cross_connect/access", + headers={"api-key": "server-api-key"}, + json={ + "id": 12, + "name": "Client User", + "login": "user@client.example.org", + "email": "user@client.example.org", + "lang": "en_US", + "groups": [ + self.env.ref("base.group_user").id, + ], + }, + ) + self.assertEqual(response.status_code, 200) + + json = response.json() + + with self._create_test_client(raise_server_exceptions=False) as test_client: + response = test_client.get( + f"/cross_connect/login/{json['client_id']}/wrong-token", + follow_redirects=False, + ) + + self.assertEqual(response.status_code, 403) diff --git a/cross_connect_server/views/fastapi_endpoint_views.xml b/cross_connect_server/views/fastapi_endpoint_views.xml new file mode 100644 index 0000000000..41f2c4660d --- /dev/null +++ b/cross_connect_server/views/fastapi_endpoint_views.xml @@ -0,0 +1,46 @@ + + + + + fastapi.endpoint + + + + + {'invisible': [('app', '==', 'cross_connect')]} + + + + + + + + + + + + + + + + + + + From 347c7fc68591cae1b30f42038ad4419920dffbad Mon Sep 17 00:00:00 2001 From: Florian da Costa Date: Thu, 3 Apr 2025 17:06:08 +0200 Subject: [PATCH 02/22] [IMP] Ensure login unicity for users coming from cross server client --- cross_connect_server/models/cross_connect_client.py | 2 +- cross_connect_server/tests/test_cross_connect_server.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cross_connect_server/models/cross_connect_client.py b/cross_connect_server/models/cross_connect_client.py index 04f5f0ed9a..f60f665335 100644 --- a/cross_connect_server/models/cross_connect_client.py +++ b/cross_connect_server/models/cross_connect_client.py @@ -73,7 +73,7 @@ def _request_access(self, access_request): lambda u: u.cross_connect_client_user_id == access_request.id ) vals = { - "login": access_request.login, + "login": f"{self.id}_{access_request.id}_{access_request.login}", "email": access_request.email, "name": access_request.name, "lang": access_request.lang, diff --git a/cross_connect_server/tests/test_cross_connect_server.py b/cross_connect_server/tests/test_cross_connect_server.py index 9006cf61a8..371ffefcd0 100644 --- a/cross_connect_server/tests/test_cross_connect_server.py +++ b/cross_connect_server/tests/test_cross_connect_server.py @@ -170,7 +170,7 @@ def test_access_ok(self): self.assertEqual(len(rc.records), 1) new_user = rc.records[0] self.assertEqual(new_user.name, "Client User") - self.assertEqual(new_user.login, "user@client.example.org") + self.assertEqual(new_user.login, f"{self.client.id}_12_user@client.example.org") self.assertEqual(new_user.email, "user@client.example.org") self.assertEqual(new_user.lang, "en_US") self.assertEqual(new_user.cross_connect_client_id.id, self.client.id) @@ -271,7 +271,9 @@ def test_access_existing(self): self.assertEqual(len(rc2.records), 0) new_user = rc.records[0] self.assertEqual(new_user.name, "Client User2") - self.assertEqual(new_user.login, "user2@client.example.org") + self.assertEqual( + new_user.login, f"{self.client.id}_12_user2@client.example.org" + ) self.assertEqual(new_user.email, "user2@client.example.org") self.assertEqual(new_user.lang, "en_US") self.assertIn(self.env.ref("fastapi.group_fastapi_user"), new_user.groups_id) From 7379916110a0e616d0edb0434ebbb09cd1287c81 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Thu, 3 Apr 2025 16:21:53 +0000 Subject: [PATCH 03/22] [UPD] Update cross_connect_server.pot --- .../i18n/cross_connect_server.pot | 209 ++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 cross_connect_server/i18n/cross_connect_server.pot diff --git a/cross_connect_server/i18n/cross_connect_server.pot b/cross_connect_server/i18n/cross_connect_server.pot new file mode 100644 index 0000000000..534c52f471 --- /dev/null +++ b/cross_connect_server/i18n/cross_connect_server.pot @@ -0,0 +1,209 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * cross_connect_server +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__api_key +msgid "API Key" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_fastapi_endpoint__app +msgid "App" +msgstr "" + +#. module: cross_connect_server +#. odoo-python +#: code:addons/cross_connect_server/routers/cross_connect.py:0 +#, python-format +msgid "Client not found" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__create_uid +msgid "Created by" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__create_date +msgid "Created on" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__allowed_group_ids +#: model:ir.model.fields,field_description:cross_connect_server.field_fastapi_endpoint__cross_connect_allowed_group_ids +msgid "Cross Connect Allowed Groups" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model,name:cross_connect_server.model_cross_connect_client +#: model:ir.model.fields,field_description:cross_connect_server.field_res_users__cross_connect_client_id +msgid "Cross Connect Client" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_res_users__cross_connect_client_user_id +msgid "Cross Connect Client User ID" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_fastapi_endpoint__cross_connect_client_ids +msgid "Cross Connect Clients" +msgstr "" + +#. module: cross_connect_server +#: model_terms:ir.ui.view,arch_db:cross_connect_server.fastapi_endpoint_form_view +msgid "Cross Connect Configuration" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields.selection,name:cross_connect_server.selection__fastapi_endpoint__app__cross_connect +msgid "Cross Connect Endpoint" +msgstr "" + +#. module: cross_connect_server +#: model:res.groups,name:cross_connect_server.group_cross_connect_manager +msgid "Cross Connect Manager" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_fastapi_endpoint__cross_connect_secret_key +msgid "Cross Connect Secret Key" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__user_count +msgid "Cross Connected User Count" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__display_name +msgid "Display Name" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__endpoint_id +msgid "Endpoint" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model,name:cross_connect_server.model_fastapi_endpoint +msgid "FastAPI Endpoint" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__group_ids +msgid "Groups" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__id +msgid "ID" +msgstr "" + +#. module: cross_connect_server +#. odoo-python +#: code:addons/cross_connect_server/models/cross_connect_client.py:0 +#: code:addons/cross_connect_server/models/cross_connect_client.py:0 +#, python-format +msgid "Invalid Token" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client____last_update +msgid "Last Modified on" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__write_date +msgid "Last Updated on" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__name +msgid "Name" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__server_env_defaults +msgid "Server Env Defaults" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__api_key +msgid "The API key to give to configure on the client." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_fastapi_endpoint__cross_connect_client_ids +msgid "The clients that can access this endpoint." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_res_users__cross_connect_client_id +msgid "The cross connect client that created this user." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__allowed_group_ids +#: model:ir.model.fields,help:cross_connect_server.field_fastapi_endpoint__cross_connect_allowed_group_ids +msgid "The groups that can access the cross connect clients of this endpoint." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__group_ids +msgid "The groups that this client belongs to." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__user_count +msgid "The number of users created by this cross connection." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_fastapi_endpoint__cross_connect_secret_key +msgid "The secret key used for cross connection." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_res_users__cross_connect_client_user_id +msgid "The user ID on the cross connect client." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__user_ids +msgid "The users created by this cross connection." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model,name:cross_connect_server.model_res_users +msgid "User" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__user_ids +msgid "Users" +msgstr "" + +#. module: cross_connect_server +#. odoo-python +#: code:addons/cross_connect_server/models/cross_connect_client.py:0 +#, python-format +msgid "You are not allowed to access this endpoint." +msgstr "" From 71bfec8565d69bb3e1dfcf74e78402a6b650abe9 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 3 Apr 2025 16:26:25 +0000 Subject: [PATCH 04/22] [BOT] post-merge updates --- cross_connect_server/README.rst | 2 +- .../static/description/icon.png | Bin 0 -> 10254 bytes .../static/description/index.html | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 cross_connect_server/static/description/icon.png diff --git a/cross_connect_server/README.rst b/cross_connect_server/README.rst index c274ff7a11..3190888c7e 100644 --- a/cross_connect_server/README.rst +++ b/cross_connect_server/README.rst @@ -7,7 +7,7 @@ Cross Connect Server !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:e7f2983ebb91caf2611da85b500923b3a91de86fbb4577c967a2a30e0ce7e739 + !! source digest: sha256:9b79c5d9a0171f9fec42f09049c6d1cbb817a7fd4337a229574e06473cbe74c2 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/cross_connect_server/static/description/icon.png b/cross_connect_server/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1dcc49c24f364e9adf0afbc6fc0bac6dbecdeb11 GIT binary patch literal 10254 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 Connect Server !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:e7f2983ebb91caf2611da85b500923b3a91de86fbb4577c967a2a30e0ce7e739 +!! source digest: sha256:9b79c5d9a0171f9fec42f09049c6d1cbb817a7fd4337a229574e06473cbe74c2 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/server-auth Translate me on Weblate Try me on Runboat

This module allows other odoo instances, where the From 603605c0a6fff121323290fd07af613bb2602351 Mon Sep 17 00:00:00 2001 From: mymage Date: Sat, 5 Apr 2025 09:09:40 +0000 Subject: [PATCH 05/22] Added translation using Weblate (Italian) --- cross_connect_server/i18n/it.po | 210 ++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 cross_connect_server/i18n/it.po diff --git a/cross_connect_server/i18n/it.po b/cross_connect_server/i18n/it.po new file mode 100644 index 0000000000..103f666893 --- /dev/null +++ b/cross_connect_server/i18n/it.po @@ -0,0 +1,210 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * cross_connect_server +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__api_key +msgid "API Key" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_fastapi_endpoint__app +msgid "App" +msgstr "" + +#. module: cross_connect_server +#. odoo-python +#: code:addons/cross_connect_server/routers/cross_connect.py:0 +#, python-format +msgid "Client not found" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__create_uid +msgid "Created by" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__create_date +msgid "Created on" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__allowed_group_ids +#: model:ir.model.fields,field_description:cross_connect_server.field_fastapi_endpoint__cross_connect_allowed_group_ids +msgid "Cross Connect Allowed Groups" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model,name:cross_connect_server.model_cross_connect_client +#: model:ir.model.fields,field_description:cross_connect_server.field_res_users__cross_connect_client_id +msgid "Cross Connect Client" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_res_users__cross_connect_client_user_id +msgid "Cross Connect Client User ID" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_fastapi_endpoint__cross_connect_client_ids +msgid "Cross Connect Clients" +msgstr "" + +#. module: cross_connect_server +#: model_terms:ir.ui.view,arch_db:cross_connect_server.fastapi_endpoint_form_view +msgid "Cross Connect Configuration" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields.selection,name:cross_connect_server.selection__fastapi_endpoint__app__cross_connect +msgid "Cross Connect Endpoint" +msgstr "" + +#. module: cross_connect_server +#: model:res.groups,name:cross_connect_server.group_cross_connect_manager +msgid "Cross Connect Manager" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_fastapi_endpoint__cross_connect_secret_key +msgid "Cross Connect Secret Key" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__user_count +msgid "Cross Connected User Count" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__display_name +msgid "Display Name" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__endpoint_id +msgid "Endpoint" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model,name:cross_connect_server.model_fastapi_endpoint +msgid "FastAPI Endpoint" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__group_ids +msgid "Groups" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__id +msgid "ID" +msgstr "" + +#. module: cross_connect_server +#. odoo-python +#: code:addons/cross_connect_server/models/cross_connect_client.py:0 +#: code:addons/cross_connect_server/models/cross_connect_client.py:0 +#, python-format +msgid "Invalid Token" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client____last_update +msgid "Last Modified on" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__write_date +msgid "Last Updated on" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__name +msgid "Name" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__server_env_defaults +msgid "Server Env Defaults" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__api_key +msgid "The API key to give to configure on the client." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_fastapi_endpoint__cross_connect_client_ids +msgid "The clients that can access this endpoint." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_res_users__cross_connect_client_id +msgid "The cross connect client that created this user." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__allowed_group_ids +#: model:ir.model.fields,help:cross_connect_server.field_fastapi_endpoint__cross_connect_allowed_group_ids +msgid "The groups that can access the cross connect clients of this endpoint." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__group_ids +msgid "The groups that this client belongs to." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__user_count +msgid "The number of users created by this cross connection." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_fastapi_endpoint__cross_connect_secret_key +msgid "The secret key used for cross connection." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_res_users__cross_connect_client_user_id +msgid "The user ID on the cross connect client." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__user_ids +msgid "The users created by this cross connection." +msgstr "" + +#. module: cross_connect_server +#: model:ir.model,name:cross_connect_server.model_res_users +msgid "User" +msgstr "" + +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__user_ids +msgid "Users" +msgstr "" + +#. module: cross_connect_server +#. odoo-python +#: code:addons/cross_connect_server/models/cross_connect_client.py:0 +#, python-format +msgid "You are not allowed to access this endpoint." +msgstr "" From 4a06d8d71f75c3a319039d8046e4f87d68417b44 Mon Sep 17 00:00:00 2001 From: mymage Date: Fri, 16 May 2025 06:21:20 +0000 Subject: [PATCH 06/22] Translated using Weblate (Italian) Currently translated at 100.0% (37 of 37 strings) Translation: server-auth-16.0/server-auth-16.0-cross_connect_server Translate-URL: https://translation.odoo-community.org/projects/server-auth-16-0/server-auth-16-0-cross_connect_server/it/ --- cross_connect_server/i18n/it.po | 77 +++++++++++++++++---------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/cross_connect_server/i18n/it.po b/cross_connect_server/i18n/it.po index 103f666893..ff1e43c43b 100644 --- a/cross_connect_server/i18n/it.po +++ b/cross_connect_server/i18n/it.po @@ -6,112 +6,114 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: Automatically generated\n" +"PO-Revision-Date: 2025-05-16 08:24+0000\n" +"Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10.4\n" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__api_key msgid "API Key" -msgstr "" +msgstr "Chiave API" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_fastapi_endpoint__app msgid "App" -msgstr "" +msgstr "Applicazione" #. module: cross_connect_server #. odoo-python #: code:addons/cross_connect_server/routers/cross_connect.py:0 #, python-format msgid "Client not found" -msgstr "" +msgstr "Client non trovato" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__create_uid msgid "Created by" -msgstr "" +msgstr "Creato da" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__create_date msgid "Created on" -msgstr "" +msgstr "Creato il" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__allowed_group_ids #: model:ir.model.fields,field_description:cross_connect_server.field_fastapi_endpoint__cross_connect_allowed_group_ids msgid "Cross Connect Allowed Groups" -msgstr "" +msgstr "Gruppi abilitati cross-connect" #. module: cross_connect_server #: model:ir.model,name:cross_connect_server.model_cross_connect_client #: model:ir.model.fields,field_description:cross_connect_server.field_res_users__cross_connect_client_id msgid "Cross Connect Client" -msgstr "" +msgstr "Client cross-connect" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_res_users__cross_connect_client_user_id msgid "Cross Connect Client User ID" -msgstr "" +msgstr "ID utente cliente cross-connect" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_fastapi_endpoint__cross_connect_client_ids msgid "Cross Connect Clients" -msgstr "" +msgstr "Client cross-connect" #. module: cross_connect_server #: model_terms:ir.ui.view,arch_db:cross_connect_server.fastapi_endpoint_form_view msgid "Cross Connect Configuration" -msgstr "" +msgstr "Configurazione cross-connect" #. module: cross_connect_server #: model:ir.model.fields.selection,name:cross_connect_server.selection__fastapi_endpoint__app__cross_connect msgid "Cross Connect Endpoint" -msgstr "" +msgstr "Endopoint cross-connect" #. module: cross_connect_server #: model:res.groups,name:cross_connect_server.group_cross_connect_manager msgid "Cross Connect Manager" -msgstr "" +msgstr "Gestore cross-connect" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_fastapi_endpoint__cross_connect_secret_key msgid "Cross Connect Secret Key" -msgstr "" +msgstr "Chiave segreta cross-connect" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__user_count msgid "Cross Connected User Count" -msgstr "" +msgstr "Conteggio utenti cross-connect" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__display_name msgid "Display Name" -msgstr "" +msgstr "Nome visualizzato" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__endpoint_id msgid "Endpoint" -msgstr "" +msgstr "Endpoint" #. module: cross_connect_server #: model:ir.model,name:cross_connect_server.model_fastapi_endpoint msgid "FastAPI Endpoint" -msgstr "" +msgstr "Endopoint FastAPI" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__group_ids msgid "Groups" -msgstr "" +msgstr "Gruppi" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__id msgid "ID" -msgstr "" +msgstr "ID" #. module: cross_connect_server #. odoo-python @@ -119,92 +121,93 @@ msgstr "" #: code:addons/cross_connect_server/models/cross_connect_client.py:0 #, python-format msgid "Invalid Token" -msgstr "" +msgstr "Token non valido" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client____last_update msgid "Last Modified on" -msgstr "" +msgstr "Ultima modifica il" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__write_uid msgid "Last Updated by" -msgstr "" +msgstr "Ultimo aggiornamento di" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__write_date msgid "Last Updated on" -msgstr "" +msgstr "Ultimo aggiornamento il" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__name msgid "Name" -msgstr "" +msgstr "Nome" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__server_env_defaults msgid "Server Env Defaults" -msgstr "" +msgstr "Predefiniti ambiente server" #. module: cross_connect_server #: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__api_key msgid "The API key to give to configure on the client." -msgstr "" +msgstr "Chiave API da fornire per configurare il client." #. module: cross_connect_server #: model:ir.model.fields,help:cross_connect_server.field_fastapi_endpoint__cross_connect_client_ids msgid "The clients that can access this endpoint." -msgstr "" +msgstr "I client che possono accedere questo endpoint." #. module: cross_connect_server #: model:ir.model.fields,help:cross_connect_server.field_res_users__cross_connect_client_id msgid "The cross connect client that created this user." -msgstr "" +msgstr "Il client cross-connect che ha creato questo utente." #. module: cross_connect_server #: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__allowed_group_ids #: model:ir.model.fields,help:cross_connect_server.field_fastapi_endpoint__cross_connect_allowed_group_ids msgid "The groups that can access the cross connect clients of this endpoint." msgstr "" +"I gruppi che possono accedere i client cross-connect di questo endpoint." #. module: cross_connect_server #: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__group_ids msgid "The groups that this client belongs to." -msgstr "" +msgstr "I gruppi a cui appartiene questo client." #. module: cross_connect_server #: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__user_count msgid "The number of users created by this cross connection." -msgstr "" +msgstr "Il numero di utenti creati da questa cross-connect." #. module: cross_connect_server #: model:ir.model.fields,help:cross_connect_server.field_fastapi_endpoint__cross_connect_secret_key msgid "The secret key used for cross connection." -msgstr "" +msgstr "La chiave segreta usata per la cross-connect." #. module: cross_connect_server #: model:ir.model.fields,help:cross_connect_server.field_res_users__cross_connect_client_user_id msgid "The user ID on the cross connect client." -msgstr "" +msgstr "L'ID utente nel client cross-connect." #. module: cross_connect_server #: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__user_ids msgid "The users created by this cross connection." -msgstr "" +msgstr "Gli utenti creati da questa cross-connect." #. module: cross_connect_server #: model:ir.model,name:cross_connect_server.model_res_users msgid "User" -msgstr "" +msgstr "Utente" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__user_ids msgid "Users" -msgstr "" +msgstr "Utenti" #. module: cross_connect_server #. odoo-python #: code:addons/cross_connect_server/models/cross_connect_client.py:0 #, python-format msgid "You are not allowed to access this endpoint." -msgstr "" +msgstr "Non si è autorizzati ad accedere a questo endpoint." From e778ccbc9c617640f4e91e7e21a7a0bb2c924b06 Mon Sep 17 00:00:00 2001 From: mymage Date: Tue, 20 May 2025 07:47:39 +0000 Subject: [PATCH 07/22] Translated using Weblate (Italian) Currently translated at 100.0% (37 of 37 strings) Translation: server-auth-16.0/server-auth-16.0-cross_connect_server Translate-URL: https://translation.odoo-community.org/projects/server-auth-16-0/server-auth-16-0-cross_connect_server/it/ --- cross_connect_server/i18n/it.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cross_connect_server/i18n/it.po b/cross_connect_server/i18n/it.po index ff1e43c43b..782a78918f 100644 --- a/cross_connect_server/i18n/it.po +++ b/cross_connect_server/i18n/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2025-05-16 08:24+0000\n" +"PO-Revision-Date: 2025-05-20 10:26+0000\n" "Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" @@ -103,7 +103,7 @@ msgstr "Endpoint" #. module: cross_connect_server #: model:ir.model,name:cross_connect_server.model_fastapi_endpoint msgid "FastAPI Endpoint" -msgstr "Endopoint FastAPI" +msgstr "Endpoint FastAPI" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__group_ids From 39aa754228dcfe97cdf20146a65298fb2dd7a534 Mon Sep 17 00:00:00 2001 From: Florian da Costa Date: Tue, 3 Jun 2025 12:20:37 +0200 Subject: [PATCH 08/22] [FIX] No invitation email for cross server created user These users are not meant to be able to log in the normal way, it is always a redirection from another Odoo with automatic login --- cross_connect_server/models/cross_connect_client.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cross_connect_server/models/cross_connect_client.py b/cross_connect_server/models/cross_connect_client.py index f60f665335..42a615a0b6 100644 --- a/cross_connect_server/models/cross_connect_client.py +++ b/cross_connect_server/models/cross_connect_client.py @@ -83,7 +83,9 @@ def _request_access(self, access_request): } # Create user if not exists if not user: - user = self.env["res.users"].create(vals) + user = ( + self.env["res.users"].with_context(no_reset_password=True).create(vals) + ) else: user.write(vals) From 0c37760a0ec681c4a165653f41980ab06d5f4ac2 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Tue, 3 Jun 2025 15:16:40 +0000 Subject: [PATCH 09/22] [BOT] post-merge updates --- cross_connect_server/README.rst | 8 ++++-- cross_connect_server/__manifest__.py | 2 +- .../static/description/index.html | 28 +++++++++++-------- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/cross_connect_server/README.rst b/cross_connect_server/README.rst index 3190888c7e..b2a2e6989a 100644 --- a/cross_connect_server/README.rst +++ b/cross_connect_server/README.rst @@ -1,3 +1,7 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + ==================== Cross Connect Server ==================== @@ -7,13 +11,13 @@ Cross Connect Server !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:9b79c5d9a0171f9fec42f09049c6d1cbb817a7fd4337a229574e06473cbe74c2 + !! source digest: sha256:8008e84d0b38e668c79989062dede0d43276fbcbaa120effb1097b09f31e2968 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status :alt: Beta -.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--auth-lightgray.png?logo=github diff --git a/cross_connect_server/__manifest__.py b/cross_connect_server/__manifest__.py index 57e066de65..08ad498925 100644 --- a/cross_connect_server/__manifest__.py +++ b/cross_connect_server/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Cross Connect Server", - "version": "16.0.1.0.0", + "version": "16.0.1.0.1", "author": "Akretion, Odoo Community Association (OCA)", "summary": "Cross Connect Server allows Cross Connect Client to connect to it.", "category": "Tools", diff --git a/cross_connect_server/static/description/index.html b/cross_connect_server/static/description/index.html index 224be3a2b0..aab9c5fa50 100644 --- a/cross_connect_server/static/description/index.html +++ b/cross_connect_server/static/description/index.html @@ -3,7 +3,7 @@ -Cross Connect Server +README.rst -

-

Cross Connect Server

+
+ + +Odoo Community Association + +
+

Cross Connect Server

-

Beta License: AGPL-3 OCA/server-auth Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/server-auth Translate me on Weblate Try me on Runboat

This module allows other odoo instances, where the cross_connect_client module is installed and configured, users to connect directly on this odoo instance.

@@ -387,7 +392,7 @@

Cross Connect Server

-

Usage

+

Usage

First of all after installing the module, you need to configure a fastapi endpoint.

In order to do that, you need to go to the menu @@ -407,7 +412,7 @@

Usage

client will be able to give to its users.

-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -415,21 +420,21 @@

Bug Tracker

Do not contact contributors directly about support or help with technical issues.

+
From bd6eded18d01e26255dd90f1a9f141c6516fc567 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Tue, 9 Dec 2025 10:30:05 +0100 Subject: [PATCH 10/22] [FIX] cross_connect_server: Default to en_US when user lang is not available --- cross_connect_server/models/cross_connect_client.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cross_connect_server/models/cross_connect_client.py b/cross_connect_server/models/cross_connect_client.py index 42a615a0b6..121158ad57 100644 --- a/cross_connect_server/models/cross_connect_client.py +++ b/cross_connect_server/models/cross_connect_client.py @@ -72,6 +72,13 @@ def _request_access(self, access_request): user = self.user_ids.filtered( lambda u: u.cross_connect_client_user_id == access_request.id ) + + # Fallback to default lang if not installed + if access_request.lang not in [ + code for code, _name in self.env["res.lang"].get_installed() + ]: + access_request.lang = "en_US" + vals = { "login": f"{self.id}_{access_request.id}_{access_request.login}", "email": access_request.email, From 6dd3f7ae6d819d11f1046d8888b9dae25882ce35 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Tue, 9 Dec 2025 12:03:48 +0100 Subject: [PATCH 11/22] [IMP] cross_connect_server: Work with params and not server redirect_url --- cross_connect_server/models/cross_connect_client.py | 9 +++++++-- cross_connect_server/routers/cross_connect.py | 10 +++++++--- cross_connect_server/schemas.py | 1 - 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/cross_connect_server/models/cross_connect_client.py b/cross_connect_server/models/cross_connect_client.py index 121158ad57..1a79cc8ed8 100644 --- a/cross_connect_server/models/cross_connect_client.py +++ b/cross_connect_server/models/cross_connect_client.py @@ -101,7 +101,6 @@ def _request_access(self, access_request): "exp": datetime.now(tz=timezone.utc) + timedelta(minutes=2), "aud": str(self.id), "id": user.id, - "redirect_url": access_request.redirect_url or "/web", }, self.endpoint_id.cross_connect_secret_key, algorithm="HS256", @@ -124,4 +123,10 @@ def _log_from_token(self, token): if not user: raise AccessDenied(_("Invalid Token")) - return user, obj["redirect_url"] + return user + + def _get_final_redirect_url(self, **params): + """Get the final redirect url after login. + Override this method to customize the local landing action. + """ + return "/web" diff --git a/cross_connect_server/routers/cross_connect.py b/cross_connect_server/routers/cross_connect.py index 94fe4ee83c..f3dfe1992a 100644 --- a/cross_connect_server/routers/cross_connect.py +++ b/cross_connect_server/routers/cross_connect.py @@ -4,7 +4,7 @@ from typing import Annotated -from fastapi import APIRouter, Depends +from fastapi import APIRouter, Depends, Request from fastapi.responses import RedirectResponse from odoo import _, api @@ -49,12 +49,14 @@ async def login( client_id: int, token: str, env: Annotated[api.Environment, Depends(odoo_env)], + request: Request, ) -> RedirectResponse: """Log user and redirect to odoo index.""" cross_connect_client = env["cross.connect.client"].sudo().browse(client_id) if not cross_connect_client: raise MissingError(_("Client not found")) - user, redirect_url = cross_connect_client.sudo()._log_from_token(token) + params = request.query_params + user = cross_connect_client.sudo()._log_from_token(token) user = user.with_user(user) user._update_last_login() env = env(user=user.id) @@ -68,7 +70,9 @@ async def login( session.session_token = user._compute_session_token(session.sid) root.session_store.save(session) # Redirect after login - response = RedirectResponse(url=redirect_url) + response = RedirectResponse( + url=cross_connect_client._get_final_redirect_url(**params) + ) response.set_cookie( "session_id", session.sid, diff --git a/cross_connect_server/schemas.py b/cross_connect_server/schemas.py index 04e59628f7..b1295e3729 100644 --- a/cross_connect_server/schemas.py +++ b/cross_connect_server/schemas.py @@ -35,7 +35,6 @@ class AccessRequest(StrictExtendableBaseModel, extra="ignore"): email: str lang: str groups: list[int] - redirect_url: str = None class AccessResponse(StrictExtendableBaseModel): From db47d62ef31f96f77dc95f40548d4708d802d6fc Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Tue, 9 Dec 2025 12:04:29 +0100 Subject: [PATCH 12/22] [IMP] cross_connect_server: Add bypass login users by re matching --- .../models/cross_connect_client.py | 15 +++++++++++++++ cross_connect_server/routers/cross_connect.py | 5 +++++ .../views/fastapi_endpoint_views.xml | 1 + 3 files changed, 21 insertions(+) diff --git a/cross_connect_server/models/cross_connect_client.py b/cross_connect_server/models/cross_connect_client.py index 1a79cc8ed8..739aad94f3 100644 --- a/cross_connect_server/models/cross_connect_client.py +++ b/cross_connect_server/models/cross_connect_client.py @@ -1,6 +1,7 @@ # Copyright 2024 Akretion (http://www.akretion.com). # @author Florian Mounier # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import re from datetime import datetime, timedelta, timezone from secrets import token_urlsafe @@ -34,6 +35,14 @@ class CrossConnectClient(models.Model): related="endpoint_id.cross_connect_allowed_group_ids", ) + bypass_user_mail_re = fields.Char( + string="Bypass Users Email Regexes", + help=( + "If set, users with an email matching one of these regex will bypass " + "the token user/login creation. The regexes are comma separated." + ), + ) + group_ids = fields.Many2many( "res.groups", string="Groups", @@ -64,6 +73,12 @@ def _compute_user_count(self): record.user_count = len(record.user_ids) def _request_access(self, access_request): + if self.bypass_user_mail_re and any( + re.search(mail_re.strip(), access_request.email) + for mail_re in self.bypass_user_mail_re.split(",") + ): + return "bypass" + # check groups groups = self.env["res.groups"].browse(access_request.groups) if groups - self.group_ids or not groups.exists(): diff --git a/cross_connect_server/routers/cross_connect.py b/cross_connect_server/routers/cross_connect.py index f3dfe1992a..0341c9d681 100644 --- a/cross_connect_server/routers/cross_connect.py +++ b/cross_connect_server/routers/cross_connect.py @@ -56,6 +56,11 @@ async def login( if not cross_connect_client: raise MissingError(_("Client not found")) params = request.query_params + if token == "bypass": + return RedirectResponse( + url=cross_connect_client._get_final_redirect_url(bypass=True, **params) + ) + user = cross_connect_client.sudo()._log_from_token(token) user = user.with_user(user) user._update_last_login() diff --git a/cross_connect_server/views/fastapi_endpoint_views.xml b/cross_connect_server/views/fastapi_endpoint_views.xml index 41f2c4660d..06557c82ba 100644 --- a/cross_connect_server/views/fastapi_endpoint_views.xml +++ b/cross_connect_server/views/fastapi_endpoint_views.xml @@ -36,6 +36,7 @@ widget="many2many_tags" options="{'no_create': True}" /> + From 7cee529ba7e75cbfb85cc8a666cd0b57e9f4ec13 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Tue, 10 Feb 2026 12:57:32 +0000 Subject: [PATCH 13/22] [UPD] Update cross_connect_server.pot --- cross_connect_server/i18n/cross_connect_server.pot | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cross_connect_server/i18n/cross_connect_server.pot b/cross_connect_server/i18n/cross_connect_server.pot index 534c52f471..ae6fe29da5 100644 --- a/cross_connect_server/i18n/cross_connect_server.pot +++ b/cross_connect_server/i18n/cross_connect_server.pot @@ -23,6 +23,11 @@ msgstr "" msgid "App" msgstr "" +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__bypass_user_mail_re +msgid "Bypass Users Email Regexes" +msgstr "" + #. module: cross_connect_server #. odoo-python #: code:addons/cross_connect_server/routers/cross_connect.py:0 @@ -112,6 +117,13 @@ msgstr "" msgid "ID" msgstr "" +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__bypass_user_mail_re +msgid "" +"If set, users with an email matching one of these regex will bypass the " +"token user/login creation. The regexes are comma separated." +msgstr "" + #. module: cross_connect_server #. odoo-python #: code:addons/cross_connect_server/models/cross_connect_client.py:0 From 62af4d39c3374eb8e276f5a31d7bcc03719f9af4 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Tue, 10 Feb 2026 13:01:55 +0000 Subject: [PATCH 14/22] [BOT] post-merge updates --- cross_connect_server/README.rst | 2 +- cross_connect_server/__manifest__.py | 2 +- cross_connect_server/static/description/index.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cross_connect_server/README.rst b/cross_connect_server/README.rst index b2a2e6989a..7203a48753 100644 --- a/cross_connect_server/README.rst +++ b/cross_connect_server/README.rst @@ -11,7 +11,7 @@ Cross Connect Server !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:8008e84d0b38e668c79989062dede0d43276fbcbaa120effb1097b09f31e2968 + !! source digest: sha256:03b7d29200b2b3b6c3cd0ea4077f895238659de2a6b18a3c644d1761129897de !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/cross_connect_server/__manifest__.py b/cross_connect_server/__manifest__.py index 08ad498925..668396ec0b 100644 --- a/cross_connect_server/__manifest__.py +++ b/cross_connect_server/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Cross Connect Server", - "version": "16.0.1.0.1", + "version": "16.0.1.1.0", "author": "Akretion, Odoo Community Association (OCA)", "summary": "Cross Connect Server allows Cross Connect Client to connect to it.", "category": "Tools", diff --git a/cross_connect_server/static/description/index.html b/cross_connect_server/static/description/index.html index aab9c5fa50..058a5e97d9 100644 --- a/cross_connect_server/static/description/index.html +++ b/cross_connect_server/static/description/index.html @@ -372,7 +372,7 @@

Cross Connect Server

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:8008e84d0b38e668c79989062dede0d43276fbcbaa120effb1097b09f31e2968 +!! source digest: sha256:03b7d29200b2b3b6c3cd0ea4077f895238659de2a6b18a3c644d1761129897de !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/server-auth Translate me on Weblate Try me on Runboat

This module allows other odoo instances, where the From 9978ba5c1407659db554e209334276fc97ac5ed7 Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 10 Feb 2026 13:02:07 +0000 Subject: [PATCH 15/22] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: server-auth-16.0/server-auth-16.0-cross_connect_server Translate-URL: https://translation.odoo-community.org/projects/server-auth-16-0/server-auth-16-0-cross_connect_server/ --- cross_connect_server/i18n/it.po | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/cross_connect_server/i18n/it.po b/cross_connect_server/i18n/it.po index 782a78918f..375eccf83a 100644 --- a/cross_connect_server/i18n/it.po +++ b/cross_connect_server/i18n/it.po @@ -26,6 +26,11 @@ msgstr "Chiave API" msgid "App" msgstr "Applicazione" +#. module: cross_connect_server +#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__bypass_user_mail_re +msgid "Bypass Users Email Regexes" +msgstr "" + #. module: cross_connect_server #. odoo-python #: code:addons/cross_connect_server/routers/cross_connect.py:0 @@ -115,10 +120,16 @@ msgstr "Gruppi" msgid "ID" msgstr "ID" +#. module: cross_connect_server +#: model:ir.model.fields,help:cross_connect_server.field_cross_connect_client__bypass_user_mail_re +msgid "" +"If set, users with an email matching one of these regex will bypass the " +"token user/login creation. The regexes are comma separated." +msgstr "" + #. module: cross_connect_server #. odoo-python #: code:addons/cross_connect_server/models/cross_connect_client.py:0 -#: code:addons/cross_connect_server/models/cross_connect_client.py:0 #, python-format msgid "Invalid Token" msgstr "Token non valido" From b554010b0ae2eb3603a4e7161f75c43ee48d5548 Mon Sep 17 00:00:00 2001 From: mymage Date: Wed, 11 Feb 2026 08:04:22 +0000 Subject: [PATCH 16/22] Translated using Weblate (Italian) Currently translated at 100.0% (39 of 39 strings) Translation: server-auth-16.0/server-auth-16.0-cross_connect_server Translate-URL: https://translation.odoo-community.org/projects/server-auth-16-0/server-auth-16-0-cross_connect_server/it/ --- cross_connect_server/i18n/it.po | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cross_connect_server/i18n/it.po b/cross_connect_server/i18n/it.po index 375eccf83a..070e3f76f8 100644 --- a/cross_connect_server/i18n/it.po +++ b/cross_connect_server/i18n/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2025-05-20 10:26+0000\n" +"PO-Revision-Date: 2026-02-11 09:31+0000\n" "Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.10.4\n" +"X-Generator: Weblate 5.15.2\n" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__api_key @@ -29,7 +29,7 @@ msgstr "Applicazione" #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__bypass_user_mail_re msgid "Bypass Users Email Regexes" -msgstr "" +msgstr "Baypassa espressione regolare e-mail utenti" #. module: cross_connect_server #. odoo-python @@ -126,6 +126,9 @@ msgid "" "If set, users with an email matching one of these regex will bypass the " "token user/login creation. The regexes are comma separated." msgstr "" +"Se impostato, gli utenti con un indirizzo e-mail corrispondente a una di " +"queste espressioni regolari ignoreranno la creazione del token utente/" +"accesso. Le espressioni regolari sono separate da virgole." #. module: cross_connect_server #. odoo-python From 59eba8c0b451062fb268f7df46295c9644f9fcd1 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Mon, 16 Mar 2026 18:07:02 +0100 Subject: [PATCH 17/22] [IMP] cross_connect_server: pre-commit auto fixes --- cross_connect_server/models/fastapi_endpoint.py | 13 +++++++------ cross_connect_server/pyproject.toml | 3 +++ 2 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 cross_connect_server/pyproject.toml diff --git a/cross_connect_server/models/fastapi_endpoint.py b/cross_connect_server/models/fastapi_endpoint.py index 774e485346..384afbe8c6 100644 --- a/cross_connect_server/models/fastapi_endpoint.py +++ b/cross_connect_server/models/fastapi_endpoint.py @@ -1,8 +1,9 @@ # Copyright 2024 Akretion (http://www.akretion.com). # @author Florian Mounier # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from collections.abc import Callable from secrets import token_urlsafe -from typing import Annotated, Callable, Dict, List +from typing import Annotated from fastapi import APIRouter, Depends, HTTPException, status from fastapi.security import APIKeyHeader @@ -47,7 +48,7 @@ def _generate_secret_key(self): # generate random ~64 chars secret key return token_urlsafe(64) - def _get_fastapi_routers(self) -> List[APIRouter]: + def _get_fastapi_routers(self) -> list[APIRouter]: routers = super()._get_fastapi_routers() if self.app == "cross_connect": @@ -55,13 +56,13 @@ def _get_fastapi_routers(self) -> List[APIRouter]: return routers - def _get_app_dependencies_overrides(self) -> Dict[Callable, Callable]: + def _get_app_dependencies_overrides(self) -> dict[Callable, Callable]: overrides = super()._get_app_dependencies_overrides() if self.app == "cross_connect": - overrides[ - authenticated_cross_connect_client - ] = api_key_based_authenticated_cross_connect_client + overrides[authenticated_cross_connect_client] = ( + api_key_based_authenticated_cross_connect_client + ) return overrides diff --git a/cross_connect_server/pyproject.toml b/cross_connect_server/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/cross_connect_server/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" From 703c47c827c7ab221ef405bd7815f58e5944deb5 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Wed, 18 Mar 2026 16:22:33 +0100 Subject: [PATCH 18/22] [MIG] cross_connect_server: Migration to 18.0 --- cross_connect_server/README.rst | 16 ++++------ cross_connect_server/__manifest__.py | 2 +- .../models/cross_connect_client.py | 10 ++++--- .../models/fastapi_endpoint.py | 2 +- cross_connect_server/routers/cross_connect.py | 9 +++--- .../static/description/index.html | 30 ++++++++----------- .../views/fastapi_endpoint_views.xml | 10 +++---- test-requirements.txt | 1 + 8 files changed, 35 insertions(+), 45 deletions(-) diff --git a/cross_connect_server/README.rst b/cross_connect_server/README.rst index 7203a48753..4dea6cac7d 100644 --- a/cross_connect_server/README.rst +++ b/cross_connect_server/README.rst @@ -1,7 +1,3 @@ -.. image:: https://odoo-community.org/readme-banner-image - :target: https://odoo-community.org/get-involved?utm_source=readme - :alt: Odoo Community Association - ==================== Cross Connect Server ==================== @@ -17,17 +13,17 @@ Cross Connect Server .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status :alt: Beta -.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--auth-lightgray.png?logo=github - :target: https://github.com/OCA/server-auth/tree/16.0/cross_connect_server + :target: https://github.com/OCA/server-auth/tree/18.0/cross_connect_server :alt: OCA/server-auth .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/server-auth-16-0/server-auth-16-0-cross_connect_server + :target: https://translation.odoo-community.org/projects/server-auth-18-0/server-auth-18-0-cross_connect_server :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/server-auth&target_branch=16.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/server-auth&target_branch=18.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -71,7 +67,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -109,6 +105,6 @@ Current `maintainer `__: |maintainer-paradoxxxzero| -This module is part of the `OCA/server-auth `_ project on GitHub. +This module is part of the `OCA/server-auth `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/cross_connect_server/__manifest__.py b/cross_connect_server/__manifest__.py index 668396ec0b..cbdb5b22e3 100644 --- a/cross_connect_server/__manifest__.py +++ b/cross_connect_server/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Cross Connect Server", - "version": "16.0.1.1.0", + "version": "18.0.1.0.0", "author": "Akretion, Odoo Community Association (OCA)", "summary": "Cross Connect Server allows Cross Connect Client to connect to it.", "category": "Tools", diff --git a/cross_connect_server/models/cross_connect_client.py b/cross_connect_server/models/cross_connect_client.py index 739aad94f3..23637bec37 100644 --- a/cross_connect_server/models/cross_connect_client.py +++ b/cross_connect_server/models/cross_connect_client.py @@ -7,7 +7,7 @@ import jwt -from odoo import _, api, fields, models +from odoo import api, fields, models from odoo.exceptions import AccessDenied @@ -82,7 +82,9 @@ def _request_access(self, access_request): # check groups groups = self.env["res.groups"].browse(access_request.groups) if groups - self.group_ids or not groups.exists(): - raise AccessDenied(_("You are not allowed to access this endpoint.")) + raise AccessDenied( + self.env._("You are not allowed to access this endpoint.") + ) user = self.user_ids.filtered( lambda u: u.cross_connect_client_user_id == access_request.id @@ -131,12 +133,12 @@ def _log_from_token(self, token): algorithms=["HS256"], ) except jwt.PyJWTError as e: - raise AccessDenied(_("Invalid Token")) from e + raise AccessDenied(self.env._("Invalid Token")) from e user = self.env["res.users"].browse(obj["id"]) if not user: - raise AccessDenied(_("Invalid Token")) + raise AccessDenied(self.env._("Invalid Token")) return user diff --git a/cross_connect_server/models/fastapi_endpoint.py b/cross_connect_server/models/fastapi_endpoint.py index 384afbe8c6..2f212a36bb 100644 --- a/cross_connect_server/models/fastapi_endpoint.py +++ b/cross_connect_server/models/fastapi_endpoint.py @@ -67,7 +67,7 @@ def _get_app_dependencies_overrides(self) -> dict[Callable, Callable]: return overrides def _get_routing_info(self): - if self.app == "cross_connect": + if self.app == "cross_connect" and self.save_http_session: # Force to not save the HTTP session for the login to work correctly self.save_http_session = False return super()._get_routing_info() diff --git a/cross_connect_server/routers/cross_connect.py b/cross_connect_server/routers/cross_connect.py index 0341c9d681..6d4be7abfd 100644 --- a/cross_connect_server/routers/cross_connect.py +++ b/cross_connect_server/routers/cross_connect.py @@ -7,7 +7,7 @@ from fastapi import APIRouter, Depends, Request from fastapi.responses import RedirectResponse -from odoo import _, api +from odoo import api from odoo.exceptions import MissingError from odoo.http import SESSION_LIFETIME, root @@ -54,7 +54,7 @@ async def login( """Log user and redirect to odoo index.""" cross_connect_client = env["cross.connect.client"].sudo().browse(client_id) if not cross_connect_client: - raise MissingError(_("Client not found")) + raise MissingError(env._("Client not found")) params = request.query_params if token == "bypass": return RedirectResponse( @@ -73,11 +73,10 @@ async def login( session.login = user.login session.context = dict(env["res.users"].context_get()) session.session_token = user._compute_session_token(session.sid) + url = cross_connect_client._get_final_redirect_url(session=session, **params) root.session_store.save(session) # Redirect after login - response = RedirectResponse( - url=cross_connect_client._get_final_redirect_url(**params) - ) + response = RedirectResponse(url=url) response.set_cookie( "session_id", session.sid, diff --git a/cross_connect_server/static/description/index.html b/cross_connect_server/static/description/index.html index 058a5e97d9..9d297c1433 100644 --- a/cross_connect_server/static/description/index.html +++ b/cross_connect_server/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +Cross Connect Server -

+
+

Cross Connect Server

- - -Odoo Community Association - -
-

Cross Connect Server

-

Beta License: AGPL-3 OCA/server-auth Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/server-auth Translate me on Weblate Try me on Runboat

This module allows other odoo instances, where the cross_connect_client module is installed and configured, users to connect directly on this odoo instance.

@@ -392,7 +387,7 @@

Cross Connect Server

-

Usage

+

Usage

First of all after installing the module, you need to configure a fastapi endpoint.

In order to do that, you need to go to the menu @@ -412,29 +407,29 @@

Usage

client will be able to give to its users.

-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Akretion
-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -444,11 +439,10 @@

Maintainers

promote its widespread use.

Current maintainer:

paradoxxxzero

-

This module is part of the OCA/server-auth project on GitHub.

+

This module is part of the OCA/server-auth project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

-
diff --git a/cross_connect_server/views/fastapi_endpoint_views.xml b/cross_connect_server/views/fastapi_endpoint_views.xml index 06557c82ba..4330e7aacb 100644 --- a/cross_connect_server/views/fastapi_endpoint_views.xml +++ b/cross_connect_server/views/fastapi_endpoint_views.xml @@ -10,15 +10,13 @@ - - {'invisible': [('app', '==', 'cross_connect')]} - + app == 'cross_connect' - + @@ -38,7 +36,7 @@ /> - + diff --git a/test-requirements.txt b/test-requirements.txt index 2cb24f43db..265b7f6b1e 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1 +1,2 @@ responses +httpx From c9947a26e8779fc1eca1a982698be1152d5312ea Mon Sep 17 00:00:00 2001 From: Florian da Costa Date: Tue, 2 Jun 2026 12:46:29 +0200 Subject: [PATCH 19/22] [IMP] cross_connect_server: Avoid email for user each time he logs in with this module --- cross_connect_server/models/cross_connect_client.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cross_connect_server/models/cross_connect_client.py b/cross_connect_server/models/cross_connect_client.py index 23637bec37..ac1a0c1e09 100644 --- a/cross_connect_server/models/cross_connect_client.py +++ b/cross_connect_server/models/cross_connect_client.py @@ -97,7 +97,6 @@ def _request_access(self, access_request): access_request.lang = "en_US" vals = { - "login": f"{self.id}_{access_request.id}_{access_request.login}", "email": access_request.email, "name": access_request.name, "lang": access_request.lang, @@ -105,6 +104,10 @@ def _request_access(self, access_request): "cross_connect_client_id": self.id, "cross_connect_client_user_id": access_request.id, } + login = f"{self.id}_{access_request.id}_{access_request.login}" + # Avoid write of login if uncessary because it triggers an email + if not user or user.login != login: + vals["login"] = login # Create user if not exists if not user: user = ( From 5401eab400545a6032293b73667cb54b3d098df6 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Thu, 4 Jun 2026 10:47:17 +0200 Subject: [PATCH 20/22] [FIX] test-requirements.txt: Use httpx2 for new starlette release --- test-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-requirements.txt b/test-requirements.txt index 265b7f6b1e..24ef63a17b 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,2 +1,2 @@ responses -httpx +httpx2 From 045fc352277e199c3023c549375a78e9a2bfeab1 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Thu, 4 Jun 2026 08:59:08 +0000 Subject: [PATCH 21/22] [UPD] Update cross_connect_server.pot --- cross_connect_server/i18n/cross_connect_server.pot | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/cross_connect_server/i18n/cross_connect_server.pot b/cross_connect_server/i18n/cross_connect_server.pot index ae6fe29da5..a94a80aff7 100644 --- a/cross_connect_server/i18n/cross_connect_server.pot +++ b/cross_connect_server/i18n/cross_connect_server.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 16.0\n" +"Project-Id-Version: Odoo Server 18.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" @@ -31,7 +31,6 @@ msgstr "" #. module: cross_connect_server #. odoo-python #: code:addons/cross_connect_server/routers/cross_connect.py:0 -#, python-format msgid "Client not found" msgstr "" @@ -127,16 +126,9 @@ msgstr "" #. module: cross_connect_server #. odoo-python #: code:addons/cross_connect_server/models/cross_connect_client.py:0 -#: code:addons/cross_connect_server/models/cross_connect_client.py:0 -#, python-format msgid "Invalid Token" msgstr "" -#. module: cross_connect_server -#: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client____last_update -msgid "Last Modified on" -msgstr "" - #. module: cross_connect_server #: model:ir.model.fields,field_description:cross_connect_server.field_cross_connect_client__write_uid msgid "Last Updated by" @@ -216,6 +208,5 @@ msgstr "" #. module: cross_connect_server #. odoo-python #: code:addons/cross_connect_server/models/cross_connect_client.py:0 -#, python-format msgid "You are not allowed to access this endpoint." msgstr "" From 3a5062a7bbd8fdf057477151c87dec1ff9e72fb4 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 4 Jun 2026 09:02:36 +0000 Subject: [PATCH 22/22] [BOT] post-merge updates --- README.md | 1 + cross_connect_server/README.rst | 8 ++++-- .../static/description/index.html | 28 +++++++++++-------- setup/_metapackage/pyproject.toml | 3 +- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 3547bedbd3..fe5d39e0e1 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ addon | version | maintainers | summary [base_user_empty_password](base_user_empty_password/) | 18.0.1.0.0 | grindtildeath | Allows to empty password of users [base_user_show_email](base_user_show_email/) | 18.0.1.0.0 | | Untangle user login and email [cross_connect_client](cross_connect_client/) | 18.0.1.0.0 | paradoxxxzero | Cross Connect Client allows to connect to a Cross Connect Server enabled odoo instance. +[cross_connect_server](cross_connect_server/) | 18.0.1.0.0 | paradoxxxzero | Cross Connect Server allows Cross Connect Client to connect to it. [impersonate_login](impersonate_login/) | 18.0.1.1.1 | Kev-Roche | tools [password_security](password_security/) | 18.0.1.0.0 | | Allow admin to set password security requirements. [user_log_view](user_log_view/) | 18.0.1.0.0 | trojikman | Allow to see user's actions log diff --git a/cross_connect_server/README.rst b/cross_connect_server/README.rst index 4dea6cac7d..47b09192da 100644 --- a/cross_connect_server/README.rst +++ b/cross_connect_server/README.rst @@ -1,3 +1,7 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + ==================== Cross Connect Server ==================== @@ -7,13 +11,13 @@ Cross Connect Server !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:03b7d29200b2b3b6c3cd0ea4077f895238659de2a6b18a3c644d1761129897de + !! source digest: sha256:8e06d36849abc3fb24f39d812cea1cfba286939ce24ec4f861119f99393ec657 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status :alt: Beta -.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--auth-lightgray.png?logo=github diff --git a/cross_connect_server/static/description/index.html b/cross_connect_server/static/description/index.html index 9d297c1433..035e69af76 100644 --- a/cross_connect_server/static/description/index.html +++ b/cross_connect_server/static/description/index.html @@ -3,7 +3,7 @@ -Cross Connect Server +README.rst -
-

Cross Connect Server

+
+ + +Odoo Community Association + +
+

Cross Connect Server

-

Beta License: AGPL-3 OCA/server-auth Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/server-auth Translate me on Weblate Try me on Runboat

This module allows other odoo instances, where the cross_connect_client module is installed and configured, users to connect directly on this odoo instance.

@@ -387,7 +392,7 @@

Cross Connect Server

-

Usage

+

Usage

First of all after installing the module, you need to configure a fastapi endpoint.

In order to do that, you need to go to the menu @@ -407,7 +412,7 @@

Usage

client will be able to give to its users.

-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -415,21 +420,21 @@

Bug Tracker

Do not contact contributors directly about support or help with technical issues.

+
diff --git a/setup/_metapackage/pyproject.toml b/setup/_metapackage/pyproject.toml index ef86e3f77b..54ee9bd4dc 100644 --- a/setup/_metapackage/pyproject.toml +++ b/setup/_metapackage/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "odoo-addons-oca-server-auth" -version = "18.0.20260227.0" +version = "18.0.20260604.0" dependencies = [ "odoo-addon-auth_admin_passkey==18.0.*", "odoo-addon-auth_api_key==18.0.*", @@ -20,6 +20,7 @@ dependencies = [ "odoo-addon-base_user_empty_password==18.0.*", "odoo-addon-base_user_show_email==18.0.*", "odoo-addon-cross_connect_client==18.0.*", + "odoo-addon-cross_connect_server==18.0.*", "odoo-addon-impersonate_login==18.0.*", "odoo-addon-password_security==18.0.*", "odoo-addon-user_log_view==18.0.*",