From 99874a292907339e9284f13b3192d53f8478c585 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Mon, 2 Jun 2025 12:56:59 +0200 Subject: [PATCH 1/8] [ADD] auth_partner, fastapi_auth_partner --- auth_partner/README.rst | 102 ++++ auth_partner/__init__.py | 2 + auth_partner/__manifest__.py | 38 ++ auth_partner/data/email_data.xml | 67 +++ auth_partner/demo/auth_directory_demo.xml | 9 + auth_partner/demo/auth_partner_demo.xml | 8 + auth_partner/demo/res_partner_demo.xml | 7 + auth_partner/models/__init__.py | 3 + auth_partner/models/auth_directory.py | 209 ++++++++ auth_partner/models/auth_partner.py | 310 ++++++++++++ auth_partner/models/res_partner.py | 34 ++ auth_partner/readme/CONTRIBUTORS.rst | 4 + auth_partner/readme/DESCRIPTION.rst | 12 + auth_partner/readme/USAGE.rst | 8 + auth_partner/security/ir.model.access.csv | 8 + auth_partner/security/ir_rule.xml | 26 + auth_partner/security/res_group.xml | 16 + auth_partner/static/description/index.html | 447 ++++++++++++++++++ auth_partner/tests/__init__.py | 1 + auth_partner/tests/common.py | 60 +++ auth_partner/tests/test_auth_partner.py | 357 ++++++++++++++ auth_partner/views/auth_directory_view.xml | 92 ++++ auth_partner/views/auth_partner_view.xml | 98 ++++ auth_partner/views/res_partner_view.xml | 22 + auth_partner/wizards/__init__.py | 2 + .../wizard_auth_partner_force_set_password.py | 37 ++ ...d_auth_partner_force_set_password_view.xml | 38 ++ .../wizard_auth_partner_reset_password.py | 59 +++ ...izard_auth_partner_reset_password_view.xml | 42 ++ 29 files changed, 2118 insertions(+) create mode 100644 auth_partner/README.rst create mode 100644 auth_partner/__init__.py create mode 100644 auth_partner/__manifest__.py create mode 100644 auth_partner/data/email_data.xml create mode 100644 auth_partner/demo/auth_directory_demo.xml create mode 100644 auth_partner/demo/auth_partner_demo.xml create mode 100644 auth_partner/demo/res_partner_demo.xml create mode 100644 auth_partner/models/__init__.py create mode 100644 auth_partner/models/auth_directory.py create mode 100644 auth_partner/models/auth_partner.py create mode 100644 auth_partner/models/res_partner.py create mode 100644 auth_partner/readme/CONTRIBUTORS.rst create mode 100644 auth_partner/readme/DESCRIPTION.rst create mode 100644 auth_partner/readme/USAGE.rst create mode 100644 auth_partner/security/ir.model.access.csv create mode 100644 auth_partner/security/ir_rule.xml create mode 100644 auth_partner/security/res_group.xml create mode 100644 auth_partner/static/description/index.html create mode 100644 auth_partner/tests/__init__.py create mode 100644 auth_partner/tests/common.py create mode 100644 auth_partner/tests/test_auth_partner.py create mode 100644 auth_partner/views/auth_directory_view.xml create mode 100644 auth_partner/views/auth_partner_view.xml create mode 100644 auth_partner/views/res_partner_view.xml create mode 100644 auth_partner/wizards/__init__.py create mode 100644 auth_partner/wizards/wizard_auth_partner_force_set_password.py create mode 100644 auth_partner/wizards/wizard_auth_partner_force_set_password_view.xml create mode 100644 auth_partner/wizards/wizard_auth_partner_reset_password.py create mode 100644 auth_partner/wizards/wizard_auth_partner_reset_password_view.xml diff --git a/auth_partner/README.rst b/auth_partner/README.rst new file mode 100644 index 000000000..ca979ef04 --- /dev/null +++ b/auth_partner/README.rst @@ -0,0 +1,102 @@ +============ +Partner Auth +============ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:c9e735f01c49bc7974e3b9354b6157e19c7486a71626ad8eef81104b628d476b + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Frest--framework-lightgray.png?logo=github + :target: https://github.com/OCA/rest-framework/tree/16.0/auth_partner + :alt: OCA/rest-framework +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/rest-framework-16-0/rest-framework-16-0-auth_partner + :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/rest-framework&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds to the partners the ability to authenticate through directories. + +This module does not implement any routing, it only provides the basic mechanisms in a directory for: + + - Registering a partner and sending an welcome email (to validate email address): `_signup` + - Authenticating a partner: `_login` + - Validating a partner email using a token: `_validate_email` + - Impersonating: `_impersonate`, `_impersonating` + - Resetting the password with a unique token sent by mail: `_request_reset_password`, `_set_password` + - Sending an invite mail when registering a partner from odoo interface for the partner to enter a password: `_send_invite`, `_set_password` + +For a routing implementation, see the `fastapi_auth_partner <../fastapi_auth_partner>`_ module. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +This module isn't meant to be used standalone but you can still see the directories and authenticable partners in: + +Settings > Technical > Partner Authentication > Partner + +and + +Settings > Technical > Partner Authentication > Directory + + +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 +~~~~~~~~~~~~ + +* `Akretion `_: + + * Sébastien Beau + * Florian Mounier + +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. + +This module is part of the `OCA/rest-framework `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/auth_partner/__init__.py b/auth_partner/__init__.py new file mode 100644 index 000000000..aee8895e7 --- /dev/null +++ b/auth_partner/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizards diff --git a/auth_partner/__manifest__.py b/auth_partner/__manifest__.py new file mode 100644 index 000000000..99e8a94fa --- /dev/null +++ b/auth_partner/__manifest__.py @@ -0,0 +1,38 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Sébastien BEAU +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Partner Auth", + "summary": "Implements the base features for a authenticable partner", + "version": "16.0.1.0.0", + "license": "AGPL-3", + "author": "Akretion,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/rest-framework", + "depends": [ + "auth_signup", + "mail", + "queue_job", + "server_environment", + ], + "data": [ + "security/res_group.xml", + "security/ir.model.access.csv", + "security/ir_rule.xml", + "data/email_data.xml", + "wizards/wizard_auth_partner_force_set_password_view.xml", + "wizards/wizard_auth_partner_reset_password_view.xml", + "views/auth_partner_view.xml", + "views/auth_directory_view.xml", + "views/res_partner_view.xml", + ], + "demo": [ + "demo/res_partner_demo.xml", + "demo/auth_directory_demo.xml", + "demo/auth_partner_demo.xml", + ], + "external_dependencies": { + "python": ["itsdangerous", "pyjwt"], + }, +} diff --git a/auth_partner/data/email_data.xml b/auth_partner/data/email_data.xml new file mode 100644 index 000000000..92193d06d --- /dev/null +++ b/auth_partner/data/email_data.xml @@ -0,0 +1,67 @@ + + + + Auth Directory: Reset Password + noreply@example.org + Reset Password + {{object.partner_id.id}} + + + ${object.partner_id.lang} + +
+ Hi + Click on the following link to reset your password + Reset Password +
+
+
+ + + Auth Directory: Set Password + noreply@example.org + Welcome + {{object.partner_id.id}} + + + {{object.partner_id.lang}} + +
+ Hi + Welcome, your account have been created + Click on the following link to set your password + Set Password +
+
+
+ + + Auth Directory: Validate Email + noreply@example.org + Welcome + {{object.partner_id.id}} + + + {{object.partner_id.lang}} + +
+ Hi + Welcome to the site, please click on the following link to verify your email + Validate Email +
+
+
+ +
diff --git a/auth_partner/demo/auth_directory_demo.xml b/auth_partner/demo/auth_directory_demo.xml new file mode 100644 index 000000000..81708b69a --- /dev/null +++ b/auth_partner/demo/auth_directory_demo.xml @@ -0,0 +1,9 @@ + + + + Demo Auth Directory + + + + + diff --git a/auth_partner/demo/auth_partner_demo.xml b/auth_partner/demo/auth_partner_demo.xml new file mode 100644 index 000000000..93dda262c --- /dev/null +++ b/auth_partner/demo/auth_partner_demo.xml @@ -0,0 +1,8 @@ + + + + + + Super-secret$1 + + diff --git a/auth_partner/demo/res_partner_demo.xml b/auth_partner/demo/res_partner_demo.xml new file mode 100644 index 000000000..43a063524 --- /dev/null +++ b/auth_partner/demo/res_partner_demo.xml @@ -0,0 +1,7 @@ + + + + Demo auth partner + partner-auth@example.org + + diff --git a/auth_partner/models/__init__.py b/auth_partner/models/__init__.py new file mode 100644 index 000000000..6259e6d10 --- /dev/null +++ b/auth_partner/models/__init__.py @@ -0,0 +1,3 @@ +from . import auth_directory +from . import auth_partner +from . import res_partner diff --git a/auth_partner/models/auth_directory.py b/auth_partner/models/auth_directory.py new file mode 100644 index 000000000..fe2663640 --- /dev/null +++ b/auth_partner/models/auth_directory.py @@ -0,0 +1,209 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Sébastien BEAU +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from datetime import datetime, timezone +from secrets import token_urlsafe + +import jwt + +from odoo import _, fields, models +from odoo.exceptions import UserError + +from odoo.addons.queue_job.delay import chain + + +class AuthDirectory(models.Model): + _name = "auth.directory" + _description = "Auth Directory" + _inherit = "server.env.mixin" + + name = fields.Char(required=True) + auth_partner_ids = fields.One2many("auth.partner", "directory_id", "Auth Partners") + set_password_token_duration = fields.Integer( + default=1440, help="In minute, default 1440 minutes => 24h", required=True + ) + impersonating_token_duration = fields.Integer( + default=60, help="In seconds, default 60 seconds", required=True + ) + reset_password_template_id = fields.Many2one( + "mail.template", + "Mail Template Forget Password", + required=True, + default=lambda self: self.env.ref( + "auth_partner.email_reset_password", + raise_if_not_found=False, + ), + ) + set_password_template_id = fields.Many2one( + "mail.template", + "Mail Template New Password", + required=True, + default=lambda self: self.env.ref( + "auth_partner.email_set_password", + raise_if_not_found=False, + ), + ) + validate_email_template_id = fields.Many2one( + "mail.template", + "Mail Template Validate Email", + required=True, + default=lambda self: self.env.ref( + "auth_partner.email_validate_email", + raise_if_not_found=False, + ), + ) + secret_key = fields.Char( + groups="base.group_system", + required=True, + default=lambda self: self._generate_default_secret_key(), + ) + count_partner = fields.Integer(compute="_compute_count_partner") + + impersonating_user_ids = fields.Many2many( + "res.users", + "auth_directory_impersonating_user_rel", + "directory_id", + "user_id", + string="Impersonating Users", + help="These odoo users can impersonate any partner of this directory", + default=lambda self: ( + self.env.ref("base.user_root") | self.env.ref("base.user_admin") + ).ids, + groups="auth_partner.group_auth_partner_manager", + ) + force_verified_email = fields.Boolean( + help="If checked, email must be verified to be able to log in" + ) + + def _generate_default_secret_key(self): + # generate random ~64 chars secret key + return token_urlsafe(64) + + def action_regenerate_secret_key(self): + self.ensure_one() + self.secret_key = self._generate_default_secret_key() + + def _compute_count_partner(self): + data = self.env["auth.partner"].read_group( + [ + ("directory_id", "in", self.ids), + ], + ["directory_id"], + groupby=["directory_id"], + lazy=False, + ) + res = {item["directory_id"][0]: item["__count"] for item in data} + + for record in self: + record.count_partner = res.get(record.id, 0) + + def _get_template(self, type_or_template): + if isinstance(type_or_template, str): + return getattr(self, type_or_template + "_template_id", None) + return type_or_template + + def _prepare_mail_context(self, context): + return context or {} + + def _send_mail_background( + self, type_or_template, auth_partner, callback_job=None, **context + ): + """ + Send an email asynchronously to the auth_partner + using the template defined in the directory + """ + self.ensure_one() + auth_partner.ensure_one() + # Load context synchronously + context = self._prepare_mail_context(context) + + job = self.delayable()._send_mail_impl( + type_or_template, auth_partner, **context + ) + if callback_job: + job = chain(job, callback_job) + return job.delay() + + def _send_mail(self, type_or_template, auth_partner, **context): + """Send an email to the auth_partner using the template defined in the directory""" + self.ensure_one() + auth_partner.ensure_one() + context = self._prepare_mail_context(context) + + self._send_mail_impl(type_or_template, auth_partner, **context) + + def _send_mail_impl(self, type_or_template, auth_partner, **context): + template = self.sudo()._get_template(type_or_template) + if not template: + raise UserError( + _("No email template defined for %(template)s in %(directory)s") + % {"template": type_or_template, "directory": self.name} + ) + template.sudo().with_context(**context).send_mail( + auth_partner.id, force_send=True, raise_exception=True + ) + + return f"Mail {template.name} sent to {auth_partner.login}" + + def _generate_token(self, action, auth_partner, expiration_delta, key_salt=""): + # We need to sudo here as secret_key is a protected field + self = self.sudo() + return jwt.encode( + { + "exp": datetime.now(tz=timezone.utc) + expiration_delta, + "aud": str(self.id), + "action": action, + "ap": auth_partner.id, + }, + self.secret_key + key_salt, + algorithm="HS256", + ) + + def _decode_token( + self, + token, + action, + key_salt=None, + ): + # We need to sudo here as secret_key is a protected field + self = self.sudo() + key = self.secret_key + if key_salt: + try: + obj = jwt.decode( + token, algorithms=["HS256"], options={"verify_signature": False} + ) + except jwt.PyJWTError as e: + raise UserError(_("Invalid Token")) from e + probable_auth_partner = self.env["auth.partner"].browse(obj["ap"]) + if not probable_auth_partner: + raise UserError(_("Invalid Token")) + key += key_salt(probable_auth_partner) + + try: + obj = jwt.decode( + token, + key, + audience=str(self.id), + options={"require": ["exp", "aud", "ap", "action"]}, + algorithms=["HS256"], + ) + except jwt.PyJWTError as e: + raise UserError(_("Invalid Token")) from e + + auth_partner = self.env["auth.partner"].browse(obj["ap"]) + + if ( + obj["action"] != action + or not auth_partner + or auth_partner.directory_id != self + ): + raise UserError(_("Invalid token")) + + return auth_partner + + @property + def _server_env_fields(self): + return {"secret_key": {}} diff --git a/auth_partner/models/auth_partner.py b/auth_partner/models/auth_partner.py new file mode 100644 index 000000000..737e14529 --- /dev/null +++ b/auth_partner/models/auth_partner.py @@ -0,0 +1,310 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Sébastien BEAU +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import logging +from datetime import timedelta + +import passlib + +from odoo import _, api, fields, models +from odoo.exceptions import AccessDenied + +# please read passlib great documentation +# https://passlib.readthedocs.io +# https://passlib.readthedocs.io/en/stable/narr/quickstart.html#choosing-a-hash +# be carefull odoo requirements use an old version of passlib +DEFAULT_CRYPT_CONTEXT = passlib.context.CryptContext(["pbkdf2_sha512"]) + +_logger = logging.getLogger(__name__) + + +class AuthPartner(models.Model): + _name = "auth.partner" + _description = "Auth Partner" + _rec_name = "login" + + partner_id = fields.Many2one( + "res.partner", "Partner", required=True, ondelete="cascade", index=True + ) + directory_id = fields.Many2one( + "auth.directory", "Directory", required=True, index=True + ) + user_can_impersonate = fields.Boolean( + compute="_compute_user_can_impersonate", + help="Technical field to check if the user can impersonate", + ) + impersonating_user_ids = fields.Many2many( + related="directory_id.impersonating_user_ids", + ) + login = fields.Char( + compute="_compute_login", + store=True, + required=True, + index=True, + precompute=True, + ) + password = fields.Char(compute="_compute_password", inverse="_inverse_password") + encrypted_password = fields.Char(index=True) + nbr_pending_reset_sent = fields.Integer( + index=True, + help=( + "Number of pending reset sent from your customer." + "This field is usefull when after a migration from an other system " + "you ask all you customer to reset their password and you send" + "different mail depending on the number of reminder" + ), + ) + date_last_request_reset_pwd = fields.Datetime( + help="Date of the last password reset request" + ) + date_last_sucessfull_reset_pwd = fields.Datetime( + help="Date of the last sucessfull password reset" + ) + date_last_impersonation = fields.Datetime( + help="Date of the last sucessfull impersonation" + ) + + mail_verified = fields.Boolean( + help="This field is set to True when the user has clicked on the link sent by email" + ) + + _sql_constraints = [ + ( + "directory_login_uniq", + "unique (directory_id, login)", + "Login must be uniq per directory !", + ), + ] + + @api.depends("partner_id.email") + def _compute_login(self): + for record in self: + record.login = record.partner_id.email + + def _crypt_context(self): + return DEFAULT_CRYPT_CONTEXT + + def _check_no_empty(self, login, password): + # double check by security but calling this through a service should + # already have check this + if not ( + isinstance(password, str) and password and isinstance(login, str) and login + ): + _logger.warning("Invalid login/password for sign in") + raise AccessDenied() + + def _get_hashed_password(self, directory, login): + self.flush() + self.env.cr.execute( + """ + SELECT id, COALESCE(encrypted_password, '') + FROM auth_partner + WHERE login=%s AND directory_id=%s""", + (login, directory.id), + ) + hashed = self.env.cr.fetchone() + if hashed and hashed[1]: + # ensure that we have a auth.partner and this partner have a password set + return hashed + else: + raise AccessDenied() + + def _compute_password(self): + for record in self: + record.password = "" + + def _inverse_password(self): + for record in self: + ctx = record._crypt_context() + hash_ = getattr(ctx, "hash", ctx.encrypt) + record.encrypted_password = hash_(record.password) + record.password = "" + + def _prepare_partner_auth_signup(self, directory, vals): + return { + "login": vals["login"].lower(), + "password": vals["password"], + "directory_id": directory.id, + } + + def _prepare_partner_signup(self, directory, vals): + return { + "name": vals["name"], + "email": vals["login"].lower(), + "auth_partner_ids": [ + (0, 0, self._prepare_partner_auth_signup(directory, vals)) + ], + } + + @api.model + def _signup(self, directory, **kwargs): + partner = self.env["res.partner"].create( + [ + self._prepare_partner_signup(directory, kwargs), + ] + ) + auth_partner = partner.auth_partner_ids + directory._send_mail_background( + "validate_email", + auth_partner, + token=auth_partner._generate_validate_email_token(), + ) + return auth_partner + + @api.model + def _login(self, directory, login, password, **kwargs): + self._check_no_empty(login, password) + login = login.lower() + try: + _id, hashed = self._get_hashed_password(directory, login) + valid, replacement = self._crypt_context().verify_and_update( + password, hashed + ) + + auth_partner = valid and self.browse(_id) + except AccessDenied: + # We do not want to leak information about the login, + # always raise the same exception + auth_partner = None + + if not auth_partner or not auth_partner.partner_id.active: + raise AccessDenied(_("Invalid Login or Password")) + + if directory.sudo().force_verified_email and not auth_partner.mail_verified: + raise AccessDenied( + _( + "Email address not validated. Validate your email address by " + "clicking on the link in the email sent to you or request a new " + "password. " + ) + ) + + if replacement is not None: + auth_partner.encrypted_password = replacement + + return auth_partner + + @api.model + def _validate_email(self, directory, token): + auth_partner = directory._decode_token(token, "validate_email") + auth_partner.write({"mail_verified": True}) + return auth_partner + + def _get_impersonate_url(self, token, **kwargs): + # You should override this method according to the impersonation url + # your framework is using + + base = self.env["ir.config_parameter"].sudo().get_param("web.base.url") + url = f"{base}/auth/impersonate/{token}" + return url + + def _get_impersonate_action(self, token, **kwargs): + return { + "type": "ir.actions.act_url", + "url": self._get_impersonate_url(token, **kwargs), + "target": "new", + } + + def impersonate(self): + self.ensure_one() + if self.env.user not in self.impersonating_user_ids: + raise AccessDenied(_("You are not allowed to impersonate this user")) + + token = self._generate_impersonating_token() + return self._get_impersonate_action(token) + + @api.depends_context("uid") + def _compute_user_can_impersonate(self): + for record in self: + record.user_can_impersonate = self.env.user in record.impersonating_user_ids + + @api.model + def _impersonating(self, directory, token): + partner_auth = directory._decode_token( + token, + "impersonating", + key_salt=lambda auth_partner: ( + auth_partner.date_last_impersonation.isoformat() + if auth_partner.date_last_impersonation + else "never" + ), + ) + partner_auth.date_last_impersonation = fields.Datetime.now() + return partner_auth + + def _on_reset_password_sent(self): + self.ensure_one() + self.date_last_request_reset_pwd = fields.Datetime.now() + self.date_last_sucessfull_reset_pwd = None + self.nbr_pending_reset_sent += 1 + + def _send_invite(self): + self.ensure_one() + self.directory_id._send_mail_background( + "set_password", + self, + callback_job=self.delayable()._on_reset_password_sent(), + token=self._generate_set_password_token(), + ) + + def send_invite(self): + for rec in self: + rec._send_invite() + + def _request_reset_password(self): + return self.directory_id._send_mail_background( + "reset_password", + self, + callback_job=self.delayable()._on_reset_password_sent(), + token=self._generate_set_password_token(), + ) + + def _set_password(self, directory, token, password): + auth_partner = directory._decode_token( + token, + "set_password", + # See `_generate_set_password_token` for the key_salt + key_salt=lambda auth_partner: auth_partner.encrypted_password or "empty", + ) + auth_partner.write( + { + "password": password, + "mail_verified": True, + } + ) + auth_partner.date_last_sucessfull_reset_pwd = fields.Datetime.now() + auth_partner.nbr_pending_reset_sent = 0 + return auth_partner + + def _generate_set_password_token(self, expiration_delta=None): + # Here we use the current encrypted_password as key_salt to ensure that + # the token will be used to reset the password only once. + return self.directory_id._generate_token( + "set_password", + self, + expiration_delta + or timedelta(minutes=self.directory_id.set_password_token_duration), + key_salt=self.encrypted_password or "empty", + ) + + def _generate_validate_email_token(self): + return self.directory_id._generate_token( + # 30 days seem to be a good value, no need for configuration + "validate_email", + self, + timedelta(days=30), + ) + + def _generate_impersonating_token(self): + return self.directory_id._generate_token( + "impersonating", + self, + timedelta(minutes=self.directory_id.impersonating_token_duration), + key_salt=( + self.date_last_impersonation.isoformat() + if self.date_last_impersonation + else "never" + ), + ) diff --git a/auth_partner/models/res_partner.py b/auth_partner/models/res_partner.py new file mode 100644 index 000000000..0a398533d --- /dev/null +++ b/auth_partner/models/res_partner.py @@ -0,0 +1,34 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Sébastien BEAU +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + auth_partner_ids = fields.One2many("auth.partner", "partner_id", "Partner Auth") + auth_partner_count = fields.Integer( + compute="_compute_auth_partner_count", compute_sudo=True + ) + + def _compute_auth_partner_count(self): + data = self.env["auth.partner"].read_group( + [ + ("partner_id", "in", self.ids), + ], + ["partner_id"], + groupby=["partner_id"], + lazy=False, + ) + res = {item["partner_id"][0]: item["__count"] for item in data} + + for record in self: + record.auth_partner_count = res.get(record.id, 0) + + def _get_auth_partner_for_directory(self, directory): + return self.sudo().auth_partner_ids.filtered( + lambda r: r.directory_id == directory + ) diff --git a/auth_partner/readme/CONTRIBUTORS.rst b/auth_partner/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..bae3cc9a1 --- /dev/null +++ b/auth_partner/readme/CONTRIBUTORS.rst @@ -0,0 +1,4 @@ +* `Akretion `_: + + * Sébastien Beau + * Florian Mounier diff --git a/auth_partner/readme/DESCRIPTION.rst b/auth_partner/readme/DESCRIPTION.rst new file mode 100644 index 000000000..2a63b69ea --- /dev/null +++ b/auth_partner/readme/DESCRIPTION.rst @@ -0,0 +1,12 @@ +This module adds to the partners the ability to authenticate through directories. + +This module does not implement any routing, it only provides the basic mechanisms in a directory for: + + - Registering a partner and sending an welcome email (to validate email address): `_signup` + - Authenticating a partner: `_login` + - Validating a partner email using a token: `_validate_email` + - Impersonating: `_impersonate`, `_impersonating` + - Resetting the password with a unique token sent by mail: `_request_reset_password`, `_set_password` + - Sending an invite mail when registering a partner from odoo interface for the partner to enter a password: `_send_invite`, `_set_password` + +For a routing implementation, see the `fastapi_auth_partner <../fastapi_auth_partner>`_ module. diff --git a/auth_partner/readme/USAGE.rst b/auth_partner/readme/USAGE.rst new file mode 100644 index 000000000..39cb46f62 --- /dev/null +++ b/auth_partner/readme/USAGE.rst @@ -0,0 +1,8 @@ +This module isn't meant to be used standalone but you can still see the directories and authenticable partners in: + +Settings > Technical > Partner Authentication > Partner + +and + +Settings > Technical > Partner Authentication > Directory + diff --git a/auth_partner/security/ir.model.access.csv b/auth_partner/security/ir.model.access.csv new file mode 100644 index 000000000..cdcead759 --- /dev/null +++ b/auth_partner/security/ir.model.access.csv @@ -0,0 +1,8 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_auth_directory,auth_directory_system,model_auth_directory,base.group_system,1,1,1,1 +access_auth_directory_read,auth_directory_manager,model_auth_directory,group_auth_partner_manager,1,0,0,0 +access_auth_partner,auth_partner_manager,model_auth_partner,group_auth_partner_manager,1,1,1,1 +api_access_auth_partner,auth_partner_api,model_auth_partner,group_auth_partner_api,1,1,0,0 +api_access_res_partner,res_partner_api,base.model_res_partner,group_auth_partner_api,1,0,0,0 +api_access_wizard_auth_partner_reset_password,wizard_auth_partner_reset_password,model_wizard_auth_partner_reset_password,group_auth_partner_manager,1,1,1,1 +api_access_wizard_auth_partner_force_set_password,wizard_auth_partner_force_set_password,model_wizard_auth_partner_force_set_password,group_auth_partner_manager,1,1,1,1 diff --git a/auth_partner/security/ir_rule.xml b/auth_partner/security/ir_rule.xml new file mode 100644 index 000000000..01a9e6020 --- /dev/null +++ b/auth_partner/security/ir_rule.xml @@ -0,0 +1,26 @@ + + + + Auth API (res_partner) + + + [('id','=', authenticated_partner_id)] + + + + + + + + Auth API (auth_partner) + + + [('partner_id','=', authenticated_partner_id)] + + + + + + diff --git a/auth_partner/security/res_group.xml b/auth_partner/security/res_group.xml new file mode 100644 index 000000000..a912c7d2f --- /dev/null +++ b/auth_partner/security/res_group.xml @@ -0,0 +1,16 @@ + + + + API Partner Auth Manager + + + + + + API Partner Auth Access + + + diff --git a/auth_partner/static/description/index.html b/auth_partner/static/description/index.html new file mode 100644 index 000000000..15a31ebef --- /dev/null +++ b/auth_partner/static/description/index.html @@ -0,0 +1,447 @@ + + + + + +Partner Auth + + + +
+

Partner Auth

+ + +

Beta License: AGPL-3 OCA/rest-framework Translate me on Weblate Try me on Runboat

+

This module adds to the partners the ability to authenticate through directories.

+

This module does not implement any routing, it only provides the basic mechanisms in a directory for:

+
+
    +
  • Registering a partner and sending an welcome email (to validate email address): _signup
  • +
  • Authenticating a partner: _login
  • +
  • Validating a partner email using a token: _validate_email
  • +
  • Impersonating: _impersonate, _impersonating
  • +
  • Resetting the password with a unique token sent by mail: _request_reset_password, _set_password
  • +
  • Sending an invite mail when registering a partner from odoo interface for the partner to enter a password: _send_invite, _set_password
  • +
+
+

For a routing implementation, see the fastapi_auth_partner module.

+

Table of contents

+ +
+

Usage

+

This module isn’t meant to be used standalone but you can still see the directories and authenticable partners in:

+

Settings > Technical > Partner Authentication > Partner

+

and

+

Settings > Technical > Partner Authentication > Directory

+
+
+

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

+
    +
  • Akretion:
      +
    • Sébastien Beau
    • +
    • Florian Mounier
    • +
    +
  • +
+
+
+

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.

+

This module is part of the OCA/rest-framework project on GitHub.

+

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

+
+
+
+ + diff --git a/auth_partner/tests/__init__.py b/auth_partner/tests/__init__.py new file mode 100644 index 000000000..ee9a639f6 --- /dev/null +++ b/auth_partner/tests/__init__.py @@ -0,0 +1 @@ +from . import test_auth_partner diff --git a/auth_partner/tests/common.py b/auth_partner/tests/common.py new file mode 100644 index 000000000..6c6f777f6 --- /dev/null +++ b/auth_partner/tests/common.py @@ -0,0 +1,60 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from contextlib import contextmanager +from typing import Any + +from odoo.tests.common import TransactionCase + +from odoo.addons.mail.tests.common import MockEmail + + +class CommonTestAuthPartner(TransactionCase, MockEmail): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, queue_job__no_delay=True)) + + cls.partner = cls.env.ref("auth_partner.res_partner_auth_demo") + cls.other_partner = cls.partner.copy( + {"name": "Other Partner", "email": "other-partner-auth@example.org"} + ) + cls.auth_partner = cls.partner.auth_partner_ids + + cls.directory = cls.env.ref("auth_partner.demo_directory") + cls.directory.impersonating_user_ids = cls.env.ref("base.user_admin") + + cls.other_auth_partner = cls.env["auth.partner"].create( + { + "login": cls.other_partner.email, + "password": "Super-secret3", + "directory_id": cls.directory.id, + "partner_id": cls.other_partner.id, + } + ) + cls.other_directory = cls.directory.copy({"name": "Other Directory"}) + + @contextmanager + def new_mails(self): + mailmail = self.env["mail.mail"] + + class MailsProxy(mailmail.__class__): + __slots__ = ["_prev", "__weakref__"] + + def __init__(self): + object.__setattr__(self, "_prev", mailmail.search([])) + + def __getattribute__(self, name: str) -> Any: + mails = mailmail.search([]) - object.__getattribute__(self, "_prev") + return object.__getattribute__(mails, name) + + new_mails = MailsProxy() + with self.mock_mail_gateway(): + yield new_mails + + @contextmanager + def assert_no_new_mail(self): + with self.new_mails() as new_mails: + yield + self.assertFalse(new_mails) diff --git a/auth_partner/tests/test_auth_partner.py b/auth_partner/tests/test_auth_partner.py new file mode 100644 index 000000000..40d9e8478 --- /dev/null +++ b/auth_partner/tests/test_auth_partner.py @@ -0,0 +1,357 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from contextlib import contextmanager +from datetime import datetime, timedelta + +from freezegun import freeze_time + +from odoo.exceptions import AccessDenied, UserError + +from .common import CommonTestAuthPartner + + +class TestAuthPartner(CommonTestAuthPartner): + @contextmanager + def assert_no_new_mail(self): + with self.new_mails() as new_mails: + yield + self.assertFalse(new_mails) + + def test_default_secret_key(self): + self.assertGreaterEqual(len(self.directory.secret_key), 64) + + def test_login_ok(self): + with self.assert_no_new_mail(): + auth_partner = self.env["auth.partner"]._login( + self.directory, + login="partner-auth@example.org", + password="Super-secret$1", + ) + self.assertTrue(auth_partner) + + def test_login_inactive_partner(self): + self.partner.active = False + with self.assertRaisesRegex(AccessDenied, "Invalid Login or Password"): + self.env["auth.partner"]._login( + self.directory, + login="partner-auth@example.org", + password="Super-secret$1", + ) + + def test_login_no_auth(self): + self.auth_partner.unlink() + with self.assertRaisesRegex(AccessDenied, "Invalid Login or Password"): + self.env["auth.partner"]._login( + self.directory, + login="partner-auth@example.org", + password="Super-secret$1", + ) + + def test_login_wrong_password(self): + with self.assertRaisesRegex(AccessDenied, "Invalid Login or Password"): + self.env["auth.partner"]._login( + self.directory, login="partner-auth@example.org", password="wrong" + ) + + def test_login_mail_not_verified(self): + self.directory.force_verified_email = True + with self.assertRaisesRegex(AccessDenied, "Email address not validated"): + self.env["auth.partner"]._login( + self.directory, + login="partner-auth@example.org", + password="Super-secret$1", + ) + + def test_login_wrong_login(self): + with self.assertRaisesRegex(AccessDenied, "Invalid Login or Password"): + self.env["auth.partner"]._login( + self.directory, + login="partner-auth@example.com", + password="Super-secret$1", + ) + + def test_login_wrong_directory(self): + with self.assertRaisesRegex(AccessDenied, "Invalid Login or Password"): + self.env["auth.partner"]._login( + self.other_directory, + login="partner-auth@example.com", + password="Super-secret$1", + ) + + def test_signup(self): + with self.new_mails() as new_mails: + new_auth_partner = self.env["auth.partner"]._signup( + self.directory, + name="New Partner", + login="new-partner-auth@example.org", + password="NewSecret", + ) + self.assertTrue(new_auth_partner) + # Ensure we can't read the password + self.assertNotEqual(new_auth_partner.password, "NewSecret") + + self.assertEqual(len(new_mails), 1) + self.assertEqual(new_mails.subject, "Welcome") + self.assertIn("Welcome to the site, please", new_mails.body) + + auth_partner = self.env["auth.partner"]._login( + self.directory, login="new-partner-auth@example.org", password="NewSecret" + ) + self.assertTrue(auth_partner) + self.assertEqual(auth_partner, new_auth_partner) + + def test_signup_wrong_directory(self): + new_auth_partner = self.env["auth.partner"]._signup( + self.other_directory, + name="New Partner", + login="new-partner-auth@example.org", + password="NewSecret", + ) + self.assertTrue(new_auth_partner) + + with self.assertRaisesRegex(AccessDenied, "Invalid Login or Password"): + self.env["auth.partner"]._login( + self.directory, + login="new-partner-auth@example.org", + password="NewSecret", + ) + + def test_signup_same_login_other_directory(self): + new_auth_partner = self.env["auth.partner"]._signup( + self.directory, + name="New Partner", + login="new-partner-auth@example.org", + password="NewSecret", + ) + self.assertTrue(new_auth_partner) + new_auth_partner_2 = self.env["auth.partner"]._signup( + self.other_directory, + name="New Partner", + login="new-partner-auth@example.org", + password="NewSecret2", + ) + self.assertTrue(new_auth_partner_2) + self.assertNotEqual(new_auth_partner, new_auth_partner_2) + + with self.assertRaisesRegex(AccessDenied, "Invalid Login or Password"): + self.env["auth.partner"]._login( + self.directory, + login="new-partner-auth@example.org", + password="NewSecret2", + ) + + with self.assertRaisesRegex(AccessDenied, "Invalid Login or Password"): + self.env["auth.partner"]._login( + self.other_directory, + login="new-partner-auth@example.org", + password="NewSecret", + ) + + def test_validate_email_ok(self): + self.assertFalse(self.auth_partner.mail_verified) + token = self.auth_partner._generate_validate_email_token() + self.auth_partner._validate_email(self.directory, token) + self.assertTrue(self.auth_partner.mail_verified) + + def test_validate_email_required_login(self): + self.directory.force_verified_email = True + token = self.auth_partner._generate_validate_email_token() + self.auth_partner._validate_email(self.directory, token) + with self.assert_no_new_mail(): + auth_partner = self.env["auth.partner"]._login( + self.directory, + login="partner-auth@example.org", + password="Super-secret$1", + ) + self.assertTrue(auth_partner) + + def test_validate_email_wrong_token(self): + self.assertFalse(self.auth_partner.mail_verified) + with self.assertRaisesRegex(UserError, "Invalid Token"): + self.auth_partner._validate_email(self.directory, "wrong") + self.assertFalse(self.auth_partner.mail_verified) + + def test_validate_email_token(self): + with self.new_mails() as new_mails: + new_auth_partner = self.env["auth.partner"]._signup( + self.directory, + name="New Partner", + login="new-partner-auth@example.org", + password="NewSecret", + ) + self.assertFalse(new_auth_partner.mail_verified) + token = new_mails.body.split("token=")[1].split('">')[0] + new_auth_partner._validate_email(self.directory, token) + self.assertTrue(new_auth_partner.mail_verified) + + def test_impersonate_ok(self): + action = self.auth_partner.with_user( + self.env.ref("base.user_admin") + ).impersonate() + token = action["url"].split("/")[-1] + + auth_partner = self.env["auth.partner"]._impersonating(self.directory, token) + self.assertEqual(auth_partner, self.auth_partner) + + def test_impersonate_once(self): + action = self.auth_partner.with_user( + self.env.ref("base.user_admin") + ).impersonate() + token = action["url"].split("/")[-1] + + self.env["auth.partner"]._impersonating(self.directory, token) + with self.assertRaisesRegex(UserError, "Invalid Token"): + self.env["auth.partner"]._impersonating(self.directory, token) + + def test_impersonate_wrong_directory(self): + action = self.auth_partner.with_user( + self.env.ref("base.user_admin") + ).impersonate() + token = action["url"].split("/")[-1] + + with self.assertRaisesRegex(UserError, "Invalid Token"): + self.env["auth.partner"]._impersonating(self.other_directory, token) + + def test_impersonate_wrong_user(self): + with self.assertRaisesRegex(AccessDenied, "not allowed to impersonate"): + self.auth_partner.with_user(self.env.ref("base.default_user")).impersonate() + + def test_impersonate_not_expired_token(self): + self.directory.impersonating_token_duration = 100 + action = self.auth_partner.with_user( + self.env.ref("base.user_admin") + ).impersonate() + token = action["url"].split("/")[-1] + + with freeze_time(datetime.now() + timedelta(hours=1)): + self.env["auth.partner"]._impersonating(self.directory, token) + + def test_impersonate_expired_token(self): + self.directory.impersonating_token_duration = 100 + action = self.auth_partner.with_user( + self.env.ref("base.user_admin") + ).impersonate() + token = action["url"].split("/")[-1] + + with ( + freeze_time(datetime.now() + timedelta(hours=2)), + self.assertRaisesRegex(UserError, "Invalid Token"), + ): + self.env["auth.partner"]._impersonating(self.directory, token) + + def test_set_password_ok(self): + self.auth_partner._set_password( + self.directory, + self.auth_partner._generate_set_password_token(), + "ResetSecret", + ) + auth_partner = self.env["auth.partner"]._login( + self.directory, login="partner-auth@example.org", password="ResetSecret" + ) + self.assertTrue(auth_partner) + + def test_set_password_wrong_token(self): + with self.assertRaisesRegex(UserError, "Invalid Token"): + self.auth_partner._set_password(self.directory, "wrong", "ResetSecret") + + def test_set_password_once(self): + token = self.auth_partner._generate_set_password_token() + self.auth_partner._set_password(self.directory, token, "ResetSecret") + with self.assertRaisesRegex(UserError, "Invalid Token"): + self.auth_partner._set_password(self.directory, token, "ResetSecret") + + def test_set_password_not_expired_token(self): + self.directory.set_password_token_duration = 100 + token = self.auth_partner._generate_set_password_token() + + with freeze_time(datetime.now() + timedelta(hours=1)): + self.auth_partner._set_password(self.directory, token, "ResetSecret") + + auth_partner = self.env["auth.partner"]._login( + self.directory, login="partner-auth@example.org", password="ResetSecret" + ) + self.assertTrue(auth_partner) + + def test_set_password_expired_token(self): + self.directory.set_password_token_duration = 100 + token = self.auth_partner._generate_set_password_token() + + with ( + freeze_time(datetime.now() + timedelta(hours=2)), + self.assertRaisesRegex(UserError, "Invalid Token"), + ): + self.auth_partner._set_password(self.directory, token, "ResetSecret") + + def test_reset_password_ok(self): + with self.new_mails() as new_mails: + self.auth_partner._request_reset_password() + self.assertEqual(len(new_mails), 1) + self.assertEqual(new_mails.subject, "Reset Password") + self.assertIn( + "Click on the following link to reset your password", new_mails.body + ) + + token = new_mails.body.split("token=")[1].split('">')[0] + self.auth_partner._set_password(self.directory, token, "ResetSecret") + auth_partner = self.env["auth.partner"]._login( + self.directory, login="partner-auth@example.org", password="ResetSecret" + ) + self.assertTrue(auth_partner) + + def test_reset_password_wrong_partner(self): + with self.new_mails() as new_mails: + self.auth_partner._request_reset_password() + self.assertEqual(len(new_mails), 1) + self.assertEqual(new_mails.subject, "Reset Password") + self.assertIn( + "Click on the following link to reset your password", new_mails.body + ) + + token = new_mails.body.split("token=")[1].split('">')[0] + # This should probably raise instead of reseting the auth_partner password + self.other_auth_partner._set_password(self.directory, token, "ResetSecret") + with self.assertRaisesRegex(AccessDenied, "Invalid Login or Password"): + self.env["auth.partner"]._login( + self.directory, + login="other-partner-auth@example.org", + password="ResetSecret", + ) + + def test_reset_password_once(self): + with self.new_mails() as new_mails: + self.auth_partner._request_reset_password() + self.assertEqual(len(new_mails), 1) + self.assertEqual(new_mails.subject, "Reset Password") + token = new_mails.body.split("token=")[1].split('">')[0] + self.auth_partner._set_password(self.directory, token, "ResetSecret") + + with self.assertRaisesRegex(UserError, "Invalid Token"): + self.auth_partner._set_password(self.directory, token, "ResetSecret2") + + def test_send_invite_set_password_ok(self): + with self.new_mails() as new_mails: + self.auth_partner._send_invite() + self.assertEqual(len(new_mails), 1) + self.assertEqual(new_mails.subject, "Welcome") + self.assertIn("your account have been created", new_mails.body) + token = new_mails.body.split("token=")[1].split('">')[0] + + self.auth_partner._set_password(self.directory, token, "ResetSecret") + auth_partner = self.env["auth.partner"]._login( + self.directory, login="partner-auth@example.org", password="ResetSecret" + ) + self.assertTrue(auth_partner) + + def test_send_invite_set_password_once(self): + with self.new_mails() as new_mails: + self.auth_partner._send_invite() + self.assertEqual(len(new_mails), 1) + self.assertEqual(new_mails.subject, "Welcome") + + token = new_mails.body.split("token=")[1].split('">')[0] + self.auth_partner._set_password(self.directory, token, "ResetSecret") + + with self.assertRaisesRegex(UserError, "Invalid Token"): + self.auth_partner._set_password(self.directory, token, "ResetSecret2") diff --git a/auth_partner/views/auth_directory_view.xml b/auth_partner/views/auth_directory_view.xml new file mode 100644 index 000000000..1d8c58cfd --- /dev/null +++ b/auth_partner/views/auth_directory_view.xml @@ -0,0 +1,92 @@ + + + + auth.directory + + + + + + + + + auth.directory + +
+
+
+ +
+ +
+
+

+ +

+
+ + + + + + + + + + + + + + +
+
+
+
+ + + auth.directory + + + + + + + + + Directory + ir.actions.act_window + auth.directory + tree,form + + [] + {} + + + +
diff --git a/auth_partner/views/auth_partner_view.xml b/auth_partner/views/auth_partner_view.xml new file mode 100644 index 000000000..bc9459442 --- /dev/null +++ b/auth_partner/views/auth_partner_view.xml @@ -0,0 +1,98 @@ + + + + auth.partner + + + + + + + + + + + + + + + auth.partner + +
+
+
+ +
+

+ + +

+
+ + + + + + + +
+
+
+
+ + + auth.partner + + + + + + + + + + + + + Partner + ir.actions.act_window + auth.partner + tree,form + + [] + {} + + + + +
diff --git a/auth_partner/views/res_partner_view.xml b/auth_partner/views/res_partner_view.xml new file mode 100644 index 000000000..9978e92b2 --- /dev/null +++ b/auth_partner/views/res_partner_view.xml @@ -0,0 +1,22 @@ + + + + res.partner + + +
+ +
+
+
+
diff --git a/auth_partner/wizards/__init__.py b/auth_partner/wizards/__init__.py new file mode 100644 index 000000000..2f8025a36 --- /dev/null +++ b/auth_partner/wizards/__init__.py @@ -0,0 +1,2 @@ +from . import wizard_auth_partner_reset_password +from . import wizard_auth_partner_force_set_password diff --git a/auth_partner/wizards/wizard_auth_partner_force_set_password.py b/auth_partner/wizards/wizard_auth_partner_force_set_password.py new file mode 100644 index 000000000..66952d3bb --- /dev/null +++ b/auth_partner/wizards/wizard_auth_partner_force_set_password.py @@ -0,0 +1,37 @@ +# Copyright 2025 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from odoo import _, api, fields, models +from odoo.exceptions import UserError, ValidationError + + +class WizardAuthPartnerForceSetPassword(models.TransientModel): + _name = "wizard.auth.partner.force.set.password" + _description = "Wizard Partner Auth Reset Password" + + password = fields.Char(required=True) + password_confirm = fields.Char(string="Confirm Password", required=True) + + @api.constrains("password", "password_confirm") + def _check_password(self): + for wizard in self: + if wizard.password != wizard.password_confirm: + raise ValidationError( + _("Password and Confirm Password must be the same") + ) + + def action_force_set_password(self): + self.ensure_one() + if self.env.context.get("active_model") != "auth.partner": + raise UserError(_("This wizard can only be used on auth.partner")) + auth_partner_id = self.env.context.get("active_id") + if not auth_partner_id: + raise UserError(_("No active_id in context")) + + auth_partner = self.env["auth.partner"].browse(auth_partner_id) + + auth_partner.write({"password": self.password}) + + return {"type": "ir.actions.act_window_close"} diff --git a/auth_partner/wizards/wizard_auth_partner_force_set_password_view.xml b/auth_partner/wizards/wizard_auth_partner_force_set_password_view.xml new file mode 100644 index 000000000..8742520c5 --- /dev/null +++ b/auth_partner/wizards/wizard_auth_partner_force_set_password_view.xml @@ -0,0 +1,38 @@ + + + + + + wizard.auth.partner.force.set.password + +
+ + + + +
+
+ +
+
+
+ + + Set Password + wizard.auth.partner.force.set.password + form + new + + +
diff --git a/auth_partner/wizards/wizard_auth_partner_reset_password.py b/auth_partner/wizards/wizard_auth_partner_reset_password.py new file mode 100644 index 000000000..e69610877 --- /dev/null +++ b/auth_partner/wizards/wizard_auth_partner_reset_password.py @@ -0,0 +1,59 @@ +# Copyright 2024 Akretion (https://www.akretion.com). +# @author Sébastien BEAU +# @author Florian Mounier +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from datetime import datetime, timedelta + +from odoo import api, fields, models + + +class WizardAuthPartnerResetPassword(models.TransientModel): + _name = "wizard.auth.partner.reset.password" + _description = "Wizard Partner Auth Reset Password" + + delay = fields.Selection( + [ + ("manually", "Manually"), + ("6-hours", "6 Hours"), + ("2-days", "2-days"), + ("7-days", "7 Days"), + ("14-days", "14 Days"), + ], + default="6-hours", + required=True, + ) + template_id = fields.Many2one( + "mail.template", + "Mail Template", + required=True, + domain=[("model_id", "=", "auth.partner")], + ) + date_validity = fields.Datetime( + compute="_compute_date_validity", store=True, readonly=False + ) + + @api.depends("delay") + def _compute_date_validity(self): + for record in self: + if record.delay != "manually": + duration, key = record.delay.split("-") + record.date_validity = datetime.now() + timedelta( + **{key: float(duration)} + ) + + def action_reset_password(self): + expiration_delta = None + if self.delay != "manually": + duration, key = self.delay.split("-") + expiration_delta = timedelta(**{key: float(duration)}) + + for auth_partner in self.env["auth.partner"].browse( + self._context["active_ids"] + ): + auth_partner.directory_id._send_mail_background( + self.template_id, + auth_partner, + callback_job=auth_partner.delayable()._on_reset_password_sent(), + token=auth_partner._generate_set_password_token(expiration_delta), + ) diff --git a/auth_partner/wizards/wizard_auth_partner_reset_password_view.xml b/auth_partner/wizards/wizard_auth_partner_reset_password_view.xml new file mode 100644 index 000000000..f35f4ec29 --- /dev/null +++ b/auth_partner/wizards/wizard_auth_partner_reset_password_view.xml @@ -0,0 +1,42 @@ + + + + + wizard.auth.partner.reset.password + +
+ An email will be send with a token to each customer, you can specify the date until the link is valid + + + + + +
+
+ +
+
+
+ + + Send Reset Password Instruction + wizard.auth.partner.reset.password + ir.actions.act_window + form + new + + + + +
From 96fc8dc4da823d5642bc0038976a625eeef98955 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Tue, 3 Jun 2025 14:39:31 +0000 Subject: [PATCH 2/8] [UPD] Update auth_partner.pot --- auth_partner/i18n/auth_partner.pot | 554 +++++++++++++++++++++++++++++ 1 file changed, 554 insertions(+) create mode 100644 auth_partner/i18n/auth_partner.pot diff --git a/auth_partner/i18n/auth_partner.pot b/auth_partner/i18n/auth_partner.pot new file mode 100644 index 000000000..b9e8a3e77 --- /dev/null +++ b/auth_partner/i18n/auth_partner.pot @@ -0,0 +1,554 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * auth_partner +# +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: auth_partner +#: model:ir.model.fields.selection,name:auth_partner.selection__wizard_auth_partner_reset_password__delay__14-days +msgid "14 Days" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields.selection,name:auth_partner.selection__wizard_auth_partner_reset_password__delay__2-days +msgid "2-days" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields.selection,name:auth_partner.selection__wizard_auth_partner_reset_password__delay__6-hours +msgid "6 Hours" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields.selection,name:auth_partner.selection__wizard_auth_partner_reset_password__delay__7-days +msgid "7 Days" +msgstr "" + +#. module: auth_partner +#: model:mail.template,body_html:auth_partner.email_reset_password +msgid "" +"
\n" +" Hi \n" +" Click on the following link to reset your password\n" +" Reset Password\n" +"
\n" +" " +msgstr "" + +#. module: auth_partner +#: model:mail.template,body_html:auth_partner.email_validate_email +msgid "" +"
\n" +" Hi \n" +" Welcome to the site, please click on the following link to verify your email\n" +" Validate Email\n" +"
\n" +" " +msgstr "" + +#. module: auth_partner +#: model:mail.template,body_html:auth_partner.email_set_password +msgid "" +"
\n" +" Hi \n" +" Welcome, your account have been created\n" +" Click on the following link to set your password\n" +" Set Password\n" +"
\n" +" " +msgstr "" + +#. module: auth_partner +#: model:res.groups,name:auth_partner.group_auth_partner_api +msgid "API Partner Auth Access" +msgstr "" + +#. module: auth_partner +#: model:res.groups,name:auth_partner.group_auth_partner_manager +msgid "API Partner Auth Manager" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_directory_view_form +#: model_terms:ir.ui.view,arch_db:auth_partner.view_partner_form +msgid "Account" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_reset_password_view_form +msgid "" +"An email will be send with a token to each customer, you can specify the " +"date until the link is valid" +msgstr "" + +#. module: auth_partner +#: model:ir.model,name:auth_partner.model_auth_directory +msgid "Auth Directory" +msgstr "" + +#. module: auth_partner +#: model:mail.template,name:auth_partner.email_reset_password +msgid "Auth Directory: Reset Password" +msgstr "" + +#. module: auth_partner +#: model:mail.template,name:auth_partner.email_set_password +msgid "Auth Directory: Set Password" +msgstr "" + +#. module: auth_partner +#: model:mail.template,name:auth_partner.email_validate_email +msgid "Auth Directory: Validate Email" +msgstr "" + +#. module: auth_partner +#: model:ir.model,name:auth_partner.model_auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_form +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_search +msgid "Auth Partner" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_res_partner__auth_partner_count +#: model:ir.model.fields,field_description:auth_partner.field_res_users__auth_partner_count +msgid "Auth Partner Count" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__auth_partner_ids +msgid "Auth Partners" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_force_set_password_view_form +#: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_reset_password_view_form +msgid "Cancel" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__password_confirm +msgid "Confirm Password" +msgstr "" + +#. module: auth_partner +#: model:ir.model,name:auth_partner.model_res_partner +msgid "Contact" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__count_partner +msgid "Count Partner" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__create_uid +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__create_uid +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__create_uid +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__create_uid +msgid "Created by" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__create_date +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__create_date +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__create_date +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__create_date +msgid "Created on" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__date_last_impersonation +msgid "Date Last Impersonation" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__date_last_request_reset_pwd +msgid "Date Last Request Reset Pwd" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__date_last_sucessfull_reset_pwd +msgid "Date Last Sucessfull Reset Pwd" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__date_validity +msgid "Date Validity" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_partner__date_last_request_reset_pwd +msgid "Date of the last password reset request" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_partner__date_last_impersonation +msgid "Date of the last sucessfull impersonation" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_partner__date_last_sucessfull_reset_pwd +msgid "Date of the last sucessfull password reset" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__delay +msgid "Delay" +msgstr "" + +#. module: auth_partner +#: model:ir.actions.act_window,name:auth_partner.auth_directory_action +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__directory_id +#: model:ir.ui.menu,name:auth_partner.auth_directory_menu +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_search +msgid "Directory" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_directory_view_form +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_directory_view_search +msgid "Directory Auth" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__display_name +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__display_name +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__display_name +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__display_name +msgid "Display Name" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/models/auth_partner.py:0 +#, python-format +msgid "" +"Email address not validated. Validate your email address by clicking on the " +"link in the email sent to you or request a new password. " +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__encrypted_password +msgid "Encrypted Password" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__force_verified_email +msgid "Force Verified Email" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_search +msgid "Group By" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__id +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__id +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__id +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__id +msgid "ID" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_directory__force_verified_email +msgid "If checked, email must be verified to be able to log in" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_form +msgid "Impersonate" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__impersonating_token_duration +msgid "Impersonating Token Duration" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__impersonating_user_ids +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__impersonating_user_ids +msgid "Impersonating Users" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_directory__set_password_token_duration +msgid "In minute, default 1440 minutes => 24h" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_directory__impersonating_token_duration +msgid "In seconds, default 60 seconds" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/models/auth_partner.py:0 +#, python-format +msgid "Invalid Login or Password" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/models/auth_directory.py:0 +#: code:addons/auth_partner/models/auth_directory.py:0 +#: code:addons/auth_partner/models/auth_directory.py:0 +#, python-format +msgid "Invalid Token" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/models/auth_directory.py:0 +#, python-format +msgid "Invalid token" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_force_set_password_view_form +#: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_reset_password_view_form +msgid "Label" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory____last_update +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner____last_update +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password____last_update +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password____last_update +msgid "Last Modified on" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__write_uid +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__write_uid +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__write_uid +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__write_date +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__write_date +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__write_date +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__write_date +msgid "Last Updated on" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__login +msgid "Login" +msgstr "" + +#. module: auth_partner +#: model:ir.model.constraint,message:auth_partner.constraint_auth_partner_directory_login_uniq +msgid "Login must be uniq per directory !" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__template_id +msgid "Mail Template" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__reset_password_template_id +msgid "Mail Template Forget Password" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__set_password_template_id +msgid "Mail Template New Password" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__validate_email_template_id +msgid "Mail Template Validate Email" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__mail_verified +msgid "Mail Verified" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields.selection,name:auth_partner.selection__wizard_auth_partner_reset_password__delay__manually +msgid "Manually" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__name +msgid "Name" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__nbr_pending_reset_sent +msgid "Nbr Pending Reset Sent" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/wizards/wizard_auth_partner_force_set_password.py:0 +#, python-format +msgid "No active_id in context" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/models/auth_directory.py:0 +#, python-format +msgid "No email template defined for %(template)s in %(directory)s" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_partner__nbr_pending_reset_sent +msgid "" +"Number of pending reset sent from your customer.This field is usefull when " +"after a migration from an other system you ask all you customer to reset " +"their password and you senddifferent mail depending on the number of " +"reminder" +msgstr "" + +#. module: auth_partner +#: model:ir.actions.act_window,name:auth_partner.auth_partner_action +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__partner_id +#: model:ir.ui.menu,name:auth_partner.auth_partner_menu +msgid "Partner" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_res_partner__auth_partner_ids +#: model:ir.model.fields,field_description:auth_partner.field_res_users__auth_partner_ids +msgid "Partner Auth" +msgstr "" + +#. module: auth_partner +#: model:ir.ui.menu,name:auth_partner.auth +msgid "Partner Authentication" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__password +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__password +msgid "Password" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/wizards/wizard_auth_partner_force_set_password.py:0 +#, python-format +msgid "Password and Confirm Password must be the same" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_directory_view_form +msgid "Regenerate secret key" +msgstr "" + +#. module: auth_partner +#: model:mail.template,subject:auth_partner.email_reset_password +msgid "Reset Password" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__secret_key +msgid "Secret Key" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__secret_key_env_default +msgid "Secret Key Env Default" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__secret_key_env_is_editable +msgid "Secret Key Env Is Editable" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_form +msgid "Send Invite" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_reset_password_view_form +msgid "Send Reset Password" +msgstr "" + +#. module: auth_partner +#: model:ir.actions.act_window,name:auth_partner.auth_partner_action_reset_password +msgid "Send Reset Password Instruction" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__server_env_defaults +msgid "Server Env Defaults" +msgstr "" + +#. module: auth_partner +#: model:ir.actions.act_window,name:auth_partner.auth_partner_force_set_password_action +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_form +#: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_force_set_password_view_form +msgid "Set Password" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__set_password_token_duration +msgid "Set Password Token Duration" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_partner__user_can_impersonate +msgid "Technical field to check if the user can impersonate" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_directory__impersonating_user_ids +#: model:ir.model.fields,help:auth_partner.field_auth_partner__impersonating_user_ids +msgid "These odoo users can impersonate any partner of this directory" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_partner__mail_verified +msgid "" +"This field is set to True when the user has clicked on the link sent by " +"email" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/wizards/wizard_auth_partner_force_set_password.py:0 +#, python-format +msgid "This wizard can only be used on auth.partner" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__user_can_impersonate +msgid "User Can Impersonate" +msgstr "" + +#. module: auth_partner +#: model:mail.template,subject:auth_partner.email_set_password +#: model:mail.template,subject:auth_partner.email_validate_email +msgid "Welcome" +msgstr "" + +#. module: auth_partner +#: model:ir.model,name:auth_partner.model_wizard_auth_partner_force_set_password +#: model:ir.model,name:auth_partner.model_wizard_auth_partner_reset_password +msgid "Wizard Partner Auth Reset Password" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/models/auth_partner.py:0 +#, python-format +msgid "You are not allowed to impersonate this user" +msgstr "" From 77d7d35ebd9bd9204fd4dfa90ad1d8195cfacae9 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Tue, 3 Jun 2025 14:42:54 +0000 Subject: [PATCH 3/8] [BOT] post-merge updates --- auth_partner/README.rst | 8 ++++-- auth_partner/static/description/icon.png | Bin 0 -> 10254 bytes auth_partner/static/description/index.html | 28 +++++++++++++-------- 3 files changed, 23 insertions(+), 13 deletions(-) create mode 100644 auth_partner/static/description/icon.png diff --git a/auth_partner/README.rst b/auth_partner/README.rst index ca979ef04..6f646f298 100644 --- a/auth_partner/README.rst +++ b/auth_partner/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 + ============ Partner Auth ============ @@ -7,13 +11,13 @@ Partner Auth !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:c9e735f01c49bc7974e3b9354b6157e19c7486a71626ad8eef81104b628d476b + !! source digest: sha256:33a8bc75dc8127331753aa9a54fe3a5b56f7d51a23cc7e9eb0000cc55f78c689 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |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%2Frest--framework-lightgray.png?logo=github diff --git a/auth_partner/static/description/icon.png b/auth_partner/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1dcc49c24f364e9adf0afbc6fc0bac6dbecdeb11 GIT binary patch literal 10254 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 -Partner Auth +README.rst -
-

Partner Auth

+
+ + +Odoo Community Association + +
+

Partner Auth

-

Beta License: AGPL-3 OCA/rest-framework Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/rest-framework Translate me on Weblate Try me on Runboat

This module adds to the partners the ability to authenticate through directories.

This module does not implement any routing, it only provides the basic mechanisms in a directory for:

@@ -397,14 +402,14 @@

Partner Auth

-

Usage

+

Usage

This module isn’t meant to be used standalone but you can still see the directories and authenticable partners in:

Settings > Technical > Partner Authentication > Partner

and

Settings > Technical > Partner Authentication > Directory

-

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 @@ -412,15 +417,15 @@

Bug Tracker

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

-

Credits

+

Credits

-

Authors

+

Authors

  • Akretion
-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -443,5 +448,6 @@

Maintainers

+
From 154a5dcc28b245ddc3b7abcbab1838131a28755a Mon Sep 17 00:00:00 2001 From: mymage Date: Wed, 4 Jun 2025 13:27:34 +0000 Subject: [PATCH 4/8] Added translation using Weblate (Italian) --- auth_partner/i18n/it.po | 555 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 555 insertions(+) create mode 100644 auth_partner/i18n/it.po diff --git a/auth_partner/i18n/it.po b/auth_partner/i18n/it.po new file mode 100644 index 000000000..1800041ef --- /dev/null +++ b/auth_partner/i18n/it.po @@ -0,0 +1,555 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * auth_partner +# +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: auth_partner +#: model:ir.model.fields.selection,name:auth_partner.selection__wizard_auth_partner_reset_password__delay__14-days +msgid "14 Days" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields.selection,name:auth_partner.selection__wizard_auth_partner_reset_password__delay__2-days +msgid "2-days" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields.selection,name:auth_partner.selection__wizard_auth_partner_reset_password__delay__6-hours +msgid "6 Hours" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields.selection,name:auth_partner.selection__wizard_auth_partner_reset_password__delay__7-days +msgid "7 Days" +msgstr "" + +#. module: auth_partner +#: model:mail.template,body_html:auth_partner.email_reset_password +msgid "" +"
\n" +" Hi \n" +" Click on the following link to reset your password\n" +" Reset Password\n" +"
\n" +" " +msgstr "" + +#. module: auth_partner +#: model:mail.template,body_html:auth_partner.email_validate_email +msgid "" +"
\n" +" Hi \n" +" Welcome to the site, please click on the following link to verify your email\n" +" Validate Email\n" +"
\n" +" " +msgstr "" + +#. module: auth_partner +#: model:mail.template,body_html:auth_partner.email_set_password +msgid "" +"
\n" +" Hi \n" +" Welcome, your account have been created\n" +" Click on the following link to set your password\n" +" Set Password\n" +"
\n" +" " +msgstr "" + +#. module: auth_partner +#: model:res.groups,name:auth_partner.group_auth_partner_api +msgid "API Partner Auth Access" +msgstr "" + +#. module: auth_partner +#: model:res.groups,name:auth_partner.group_auth_partner_manager +msgid "API Partner Auth Manager" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_directory_view_form +#: model_terms:ir.ui.view,arch_db:auth_partner.view_partner_form +msgid "Account" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_reset_password_view_form +msgid "" +"An email will be send with a token to each customer, you can specify the " +"date until the link is valid" +msgstr "" + +#. module: auth_partner +#: model:ir.model,name:auth_partner.model_auth_directory +msgid "Auth Directory" +msgstr "" + +#. module: auth_partner +#: model:mail.template,name:auth_partner.email_reset_password +msgid "Auth Directory: Reset Password" +msgstr "" + +#. module: auth_partner +#: model:mail.template,name:auth_partner.email_set_password +msgid "Auth Directory: Set Password" +msgstr "" + +#. module: auth_partner +#: model:mail.template,name:auth_partner.email_validate_email +msgid "Auth Directory: Validate Email" +msgstr "" + +#. module: auth_partner +#: model:ir.model,name:auth_partner.model_auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_form +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_search +msgid "Auth Partner" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_res_partner__auth_partner_count +#: model:ir.model.fields,field_description:auth_partner.field_res_users__auth_partner_count +msgid "Auth Partner Count" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__auth_partner_ids +msgid "Auth Partners" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_force_set_password_view_form +#: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_reset_password_view_form +msgid "Cancel" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__password_confirm +msgid "Confirm Password" +msgstr "" + +#. module: auth_partner +#: model:ir.model,name:auth_partner.model_res_partner +msgid "Contact" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__count_partner +msgid "Count Partner" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__create_uid +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__create_uid +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__create_uid +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__create_uid +msgid "Created by" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__create_date +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__create_date +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__create_date +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__create_date +msgid "Created on" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__date_last_impersonation +msgid "Date Last Impersonation" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__date_last_request_reset_pwd +msgid "Date Last Request Reset Pwd" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__date_last_sucessfull_reset_pwd +msgid "Date Last Sucessfull Reset Pwd" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__date_validity +msgid "Date Validity" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_partner__date_last_request_reset_pwd +msgid "Date of the last password reset request" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_partner__date_last_impersonation +msgid "Date of the last sucessfull impersonation" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_partner__date_last_sucessfull_reset_pwd +msgid "Date of the last sucessfull password reset" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__delay +msgid "Delay" +msgstr "" + +#. module: auth_partner +#: model:ir.actions.act_window,name:auth_partner.auth_directory_action +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__directory_id +#: model:ir.ui.menu,name:auth_partner.auth_directory_menu +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_search +msgid "Directory" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_directory_view_form +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_directory_view_search +msgid "Directory Auth" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__display_name +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__display_name +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__display_name +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__display_name +msgid "Display Name" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/models/auth_partner.py:0 +#, python-format +msgid "" +"Email address not validated. Validate your email address by clicking on the " +"link in the email sent to you or request a new password. " +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__encrypted_password +msgid "Encrypted Password" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__force_verified_email +msgid "Force Verified Email" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_search +msgid "Group By" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__id +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__id +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__id +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__id +msgid "ID" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_directory__force_verified_email +msgid "If checked, email must be verified to be able to log in" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_form +msgid "Impersonate" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__impersonating_token_duration +msgid "Impersonating Token Duration" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__impersonating_user_ids +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__impersonating_user_ids +msgid "Impersonating Users" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_directory__set_password_token_duration +msgid "In minute, default 1440 minutes => 24h" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_directory__impersonating_token_duration +msgid "In seconds, default 60 seconds" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/models/auth_partner.py:0 +#, python-format +msgid "Invalid Login or Password" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/models/auth_directory.py:0 +#: code:addons/auth_partner/models/auth_directory.py:0 +#: code:addons/auth_partner/models/auth_directory.py:0 +#, python-format +msgid "Invalid Token" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/models/auth_directory.py:0 +#, python-format +msgid "Invalid token" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_force_set_password_view_form +#: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_reset_password_view_form +msgid "Label" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory____last_update +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner____last_update +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password____last_update +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password____last_update +msgid "Last Modified on" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__write_uid +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__write_uid +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__write_uid +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__write_date +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__write_date +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__write_date +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__write_date +msgid "Last Updated on" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__login +msgid "Login" +msgstr "" + +#. module: auth_partner +#: model:ir.model.constraint,message:auth_partner.constraint_auth_partner_directory_login_uniq +msgid "Login must be uniq per directory !" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__template_id +msgid "Mail Template" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__reset_password_template_id +msgid "Mail Template Forget Password" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__set_password_template_id +msgid "Mail Template New Password" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__validate_email_template_id +msgid "Mail Template Validate Email" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__mail_verified +msgid "Mail Verified" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields.selection,name:auth_partner.selection__wizard_auth_partner_reset_password__delay__manually +msgid "Manually" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__name +msgid "Name" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__nbr_pending_reset_sent +msgid "Nbr Pending Reset Sent" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/wizards/wizard_auth_partner_force_set_password.py:0 +#, python-format +msgid "No active_id in context" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/models/auth_directory.py:0 +#, python-format +msgid "No email template defined for %(template)s in %(directory)s" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_partner__nbr_pending_reset_sent +msgid "" +"Number of pending reset sent from your customer.This field is usefull when " +"after a migration from an other system you ask all you customer to reset " +"their password and you senddifferent mail depending on the number of " +"reminder" +msgstr "" + +#. module: auth_partner +#: model:ir.actions.act_window,name:auth_partner.auth_partner_action +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__partner_id +#: model:ir.ui.menu,name:auth_partner.auth_partner_menu +msgid "Partner" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_res_partner__auth_partner_ids +#: model:ir.model.fields,field_description:auth_partner.field_res_users__auth_partner_ids +msgid "Partner Auth" +msgstr "" + +#. module: auth_partner +#: model:ir.ui.menu,name:auth_partner.auth +msgid "Partner Authentication" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__password +#: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__password +msgid "Password" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/wizards/wizard_auth_partner_force_set_password.py:0 +#, python-format +msgid "Password and Confirm Password must be the same" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_directory_view_form +msgid "Regenerate secret key" +msgstr "" + +#. module: auth_partner +#: model:mail.template,subject:auth_partner.email_reset_password +msgid "Reset Password" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__secret_key +msgid "Secret Key" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__secret_key_env_default +msgid "Secret Key Env Default" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__secret_key_env_is_editable +msgid "Secret Key Env Is Editable" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_form +msgid "Send Invite" +msgstr "" + +#. module: auth_partner +#: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_reset_password_view_form +msgid "Send Reset Password" +msgstr "" + +#. module: auth_partner +#: model:ir.actions.act_window,name:auth_partner.auth_partner_action_reset_password +msgid "Send Reset Password Instruction" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__server_env_defaults +msgid "Server Env Defaults" +msgstr "" + +#. module: auth_partner +#: model:ir.actions.act_window,name:auth_partner.auth_partner_force_set_password_action +#: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_form +#: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_force_set_password_view_form +msgid "Set Password" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_directory__set_password_token_duration +msgid "Set Password Token Duration" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_partner__user_can_impersonate +msgid "Technical field to check if the user can impersonate" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_directory__impersonating_user_ids +#: model:ir.model.fields,help:auth_partner.field_auth_partner__impersonating_user_ids +msgid "These odoo users can impersonate any partner of this directory" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,help:auth_partner.field_auth_partner__mail_verified +msgid "" +"This field is set to True when the user has clicked on the link sent by " +"email" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/wizards/wizard_auth_partner_force_set_password.py:0 +#, python-format +msgid "This wizard can only be used on auth.partner" +msgstr "" + +#. module: auth_partner +#: model:ir.model.fields,field_description:auth_partner.field_auth_partner__user_can_impersonate +msgid "User Can Impersonate" +msgstr "" + +#. module: auth_partner +#: model:mail.template,subject:auth_partner.email_set_password +#: model:mail.template,subject:auth_partner.email_validate_email +msgid "Welcome" +msgstr "" + +#. module: auth_partner +#: model:ir.model,name:auth_partner.model_wizard_auth_partner_force_set_password +#: model:ir.model,name:auth_partner.model_wizard_auth_partner_reset_password +msgid "Wizard Partner Auth Reset Password" +msgstr "" + +#. module: auth_partner +#. odoo-python +#: code:addons/auth_partner/models/auth_partner.py:0 +#, python-format +msgid "You are not allowed to impersonate this user" +msgstr "" From 79e171f999da69d78ca100e2d50fba42e5e993bf Mon Sep 17 00:00:00 2001 From: mymage Date: Wed, 25 Jun 2025 07:16:15 +0000 Subject: [PATCH 5/8] Translated using Weblate (Italian) Currently translated at 100.0% (90 of 90 strings) Translation: rest-framework-16.0/rest-framework-16.0-auth_partner Translate-URL: https://translation.odoo-community.org/projects/rest-framework-16-0/rest-framework-16-0-auth_partner/it/ --- auth_partner/i18n/it.po | 209 ++++++++++++++++++++++++---------------- 1 file changed, 126 insertions(+), 83 deletions(-) diff --git a/auth_partner/i18n/it.po b/auth_partner/i18n/it.po index 1800041ef..a67f0f833 100644 --- a/auth_partner/i18n/it.po +++ b/auth_partner/i18n/it.po @@ -6,33 +6,35 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: Automatically generated\n" +"PO-Revision-Date: 2025-06-25 09:25+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: auth_partner #: model:ir.model.fields.selection,name:auth_partner.selection__wizard_auth_partner_reset_password__delay__14-days msgid "14 Days" -msgstr "" +msgstr "14 Giorni" #. module: auth_partner #: model:ir.model.fields.selection,name:auth_partner.selection__wizard_auth_partner_reset_password__delay__2-days msgid "2-days" -msgstr "" +msgstr "2 Giorni" #. module: auth_partner #: model:ir.model.fields.selection,name:auth_partner.selection__wizard_auth_partner_reset_password__delay__6-hours msgid "6 Hours" -msgstr "" +msgstr "6 Ore" #. module: auth_partner #: model:ir.model.fields.selection,name:auth_partner.selection__wizard_auth_partner_reset_password__delay__7-days msgid "7 Days" -msgstr "" +msgstr "7 Giorni" #. module: auth_partner #: model:mail.template,body_html:auth_partner.email_reset_password @@ -44,6 +46,15 @@ msgid "" " \n" " " msgstr "" +"
\n" +" Salve \n" +" fare clic sul seguente collegamento per resettare la passwrod\n" +" Resetta " +"password\n" +"
\n" +" " #. module: auth_partner #: model:mail.template,body_html:auth_partner.email_validate_email @@ -55,6 +66,16 @@ msgid "" " \n" " " msgstr "" +"
\n" +" Salve \n" +" Benvenuto sul sito, clicca sul seguente collegamento per " +"verificare la tua e-mail\n" +" Valida " +"e-mail\n" +"
\n" +" " #. module: auth_partner #: model:mail.template,body_html:auth_partner.email_set_password @@ -67,22 +88,32 @@ msgid "" " \n" " " msgstr "" +"
\n" +" Salve \n" +" Benvenuto, il tuo account è stato creato\n" +" Clicca sul collegamento seguente per impostare la tua password\n" +" Imposta " +"password\n" +"
\n" +" " #. module: auth_partner #: model:res.groups,name:auth_partner.group_auth_partner_api msgid "API Partner Auth Access" -msgstr "" +msgstr "Autorizzazione accesso API del partner" #. module: auth_partner #: model:res.groups,name:auth_partner.group_auth_partner_manager msgid "API Partner Auth Manager" -msgstr "" +msgstr "Responsabile autorizzazione API del partner" #. module: auth_partner #: model_terms:ir.ui.view,arch_db:auth_partner.auth_directory_view_form #: model_terms:ir.ui.view,arch_db:auth_partner.view_partner_form msgid "Account" -msgstr "" +msgstr "Conto" #. module: auth_partner #: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_reset_password_view_form @@ -90,65 +121,67 @@ msgid "" "An email will be send with a token to each customer, you can specify the " "date until the link is valid" msgstr "" +"Verrà inviata una e-mail con un token ad ogni cliente, si può indicare la " +"data entro cui il collegamento è valido" #. module: auth_partner #: model:ir.model,name:auth_partner.model_auth_directory msgid "Auth Directory" -msgstr "" +msgstr "Cartella autorizzazione" #. module: auth_partner #: model:mail.template,name:auth_partner.email_reset_password msgid "Auth Directory: Reset Password" -msgstr "" +msgstr "Cartella autorizzazione: reimposta password" #. module: auth_partner #: model:mail.template,name:auth_partner.email_set_password msgid "Auth Directory: Set Password" -msgstr "" +msgstr "Cartella autorizzazione: imposta password" #. module: auth_partner #: model:mail.template,name:auth_partner.email_validate_email msgid "Auth Directory: Validate Email" -msgstr "" +msgstr "Cartella autorizzazione: valida e-mail" #. module: auth_partner #: model:ir.model,name:auth_partner.model_auth_partner #: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_form #: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_search msgid "Auth Partner" -msgstr "" +msgstr "Partner autorizzazione" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_res_partner__auth_partner_count #: model:ir.model.fields,field_description:auth_partner.field_res_users__auth_partner_count msgid "Auth Partner Count" -msgstr "" +msgstr "Conteggio partner autorizzazione" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__auth_partner_ids msgid "Auth Partners" -msgstr "" +msgstr "Partner autorizzazione" #. module: auth_partner #: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_force_set_password_view_form #: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_reset_password_view_form msgid "Cancel" -msgstr "" +msgstr "Annulla" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__password_confirm msgid "Confirm Password" -msgstr "" +msgstr "Conferma password" #. module: auth_partner #: model:ir.model,name:auth_partner.model_res_partner msgid "Contact" -msgstr "" +msgstr "Contatto" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__count_partner msgid "Count Partner" -msgstr "" +msgstr "Conteggio partner" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__create_uid @@ -156,7 +189,7 @@ msgstr "" #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__create_uid #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__create_uid msgid "Created by" -msgstr "" +msgstr "Creato da" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__create_date @@ -164,47 +197,47 @@ msgstr "" #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__create_date #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__create_date msgid "Created on" -msgstr "" +msgstr "Creato il" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_partner__date_last_impersonation msgid "Date Last Impersonation" -msgstr "" +msgstr "Data ultima imitazione" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_partner__date_last_request_reset_pwd msgid "Date Last Request Reset Pwd" -msgstr "" +msgstr "Data ultima richiesta reimpostazione password" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_partner__date_last_sucessfull_reset_pwd msgid "Date Last Sucessfull Reset Pwd" -msgstr "" +msgstr "Data ultima reimpostazione password riuscita" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__date_validity msgid "Date Validity" -msgstr "" +msgstr "Validità data" #. module: auth_partner #: model:ir.model.fields,help:auth_partner.field_auth_partner__date_last_request_reset_pwd msgid "Date of the last password reset request" -msgstr "" +msgstr "Data ultima richiesta reimpostazione password" #. module: auth_partner #: model:ir.model.fields,help:auth_partner.field_auth_partner__date_last_impersonation msgid "Date of the last sucessfull impersonation" -msgstr "" +msgstr "Data ultima imitazione riuscita" #. module: auth_partner #: model:ir.model.fields,help:auth_partner.field_auth_partner__date_last_sucessfull_reset_pwd msgid "Date of the last sucessfull password reset" -msgstr "" +msgstr "Data ultima reimpostazione password riuscita" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__delay msgid "Delay" -msgstr "" +msgstr "Ritardo" #. module: auth_partner #: model:ir.actions.act_window,name:auth_partner.auth_directory_action @@ -212,13 +245,13 @@ msgstr "" #: model:ir.ui.menu,name:auth_partner.auth_directory_menu #: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_search msgid "Directory" -msgstr "" +msgstr "Cartella" #. module: auth_partner #: model_terms:ir.ui.view,arch_db:auth_partner.auth_directory_view_form #: model_terms:ir.ui.view,arch_db:auth_partner.auth_directory_view_search msgid "Directory Auth" -msgstr "" +msgstr "Autorizzazione cartella" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__display_name @@ -226,7 +259,7 @@ msgstr "" #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__display_name #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__display_name msgid "Display Name" -msgstr "" +msgstr "Nome visualizzato" #. module: auth_partner #. odoo-python @@ -236,21 +269,24 @@ msgid "" "Email address not validated. Validate your email address by clicking on the " "link in the email sent to you or request a new password. " msgstr "" +"Indirizzo e-mail non validato. Validare il proprio indirizzo e-mail facendo " +"click sul collegamento nella e-mail inviata per la richiesta di una nuova " +"password. " #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_partner__encrypted_password msgid "Encrypted Password" -msgstr "" +msgstr "Password criptata" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__force_verified_email msgid "Force Verified Email" -msgstr "" +msgstr "Forza e-mail verificata" #. module: auth_partner #: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_search msgid "Group By" -msgstr "" +msgstr "Raggruppa per" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__id @@ -258,45 +294,46 @@ msgstr "" #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__id #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__id msgid "ID" -msgstr "" +msgstr "ID" #. module: auth_partner #: model:ir.model.fields,help:auth_partner.field_auth_directory__force_verified_email msgid "If checked, email must be verified to be able to log in" msgstr "" +"Se selezionata, l'e-mail deve essere verificata per consentire l'accesso" #. module: auth_partner #: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_form msgid "Impersonate" -msgstr "" +msgstr "Imita" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__impersonating_token_duration msgid "Impersonating Token Duration" -msgstr "" +msgstr "Durata token imitazione" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__impersonating_user_ids #: model:ir.model.fields,field_description:auth_partner.field_auth_partner__impersonating_user_ids msgid "Impersonating Users" -msgstr "" +msgstr "Utenti imitazione" #. module: auth_partner #: model:ir.model.fields,help:auth_partner.field_auth_directory__set_password_token_duration msgid "In minute, default 1440 minutes => 24h" -msgstr "" +msgstr "In minuti,predefinito 1440 minuti => 24 ore" #. module: auth_partner #: model:ir.model.fields,help:auth_partner.field_auth_directory__impersonating_token_duration msgid "In seconds, default 60 seconds" -msgstr "" +msgstr "In secondi, predefinito 60 secondi" #. module: auth_partner #. odoo-python #: code:addons/auth_partner/models/auth_partner.py:0 #, python-format msgid "Invalid Login or Password" -msgstr "" +msgstr "Nome o password errati" #. module: auth_partner #. odoo-python @@ -305,20 +342,20 @@ msgstr "" #: code:addons/auth_partner/models/auth_directory.py:0 #, python-format msgid "Invalid Token" -msgstr "" +msgstr "Token non valido" #. module: auth_partner #. odoo-python #: code:addons/auth_partner/models/auth_directory.py:0 #, python-format msgid "Invalid token" -msgstr "" +msgstr "Token non valido" #. module: auth_partner #: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_force_set_password_view_form #: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_reset_password_view_form msgid "Label" -msgstr "" +msgstr "Etichetta" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory____last_update @@ -326,7 +363,7 @@ msgstr "" #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password____last_update #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password____last_update msgid "Last Modified on" -msgstr "" +msgstr "Ultima modifica il" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__write_uid @@ -334,7 +371,7 @@ msgstr "" #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__write_uid #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__write_uid msgid "Last Updated by" -msgstr "" +msgstr "Ultimo aggiornamento di" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__write_date @@ -342,71 +379,71 @@ msgstr "" #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__write_date #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__write_date msgid "Last Updated on" -msgstr "" +msgstr "Ultimo aggiornamento il" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_partner__login msgid "Login" -msgstr "" +msgstr "Login" #. module: auth_partner #: model:ir.model.constraint,message:auth_partner.constraint_auth_partner_directory_login_uniq msgid "Login must be uniq per directory !" -msgstr "" +msgstr "La login deve essere univoca per cartella!" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_reset_password__template_id msgid "Mail Template" -msgstr "" +msgstr "Modello e-mail" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__reset_password_template_id msgid "Mail Template Forget Password" -msgstr "" +msgstr "Modello e-mail password dimenticata" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__set_password_template_id msgid "Mail Template New Password" -msgstr "" +msgstr "Modello e-mail nuova password" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__validate_email_template_id msgid "Mail Template Validate Email" -msgstr "" +msgstr "Modello e-mail validazione e-mail" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_partner__mail_verified msgid "Mail Verified" -msgstr "" +msgstr "E-mail verificata" #. module: auth_partner #: model:ir.model.fields.selection,name:auth_partner.selection__wizard_auth_partner_reset_password__delay__manually msgid "Manually" -msgstr "" +msgstr "Manualmente" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__name msgid "Name" -msgstr "" +msgstr "Nome" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_partner__nbr_pending_reset_sent msgid "Nbr Pending Reset Sent" -msgstr "" +msgstr "N° reset inviati in attesa" #. module: auth_partner #. odoo-python #: code:addons/auth_partner/wizards/wizard_auth_partner_force_set_password.py:0 #, python-format msgid "No active_id in context" -msgstr "" +msgstr "Manca active_id nel context" #. module: auth_partner #. odoo-python #: code:addons/auth_partner/models/auth_directory.py:0 #, python-format msgid "No email template defined for %(template)s in %(directory)s" -msgstr "" +msgstr "Modello e-mail non definito per %(template)s in %(directory)s" #. module: auth_partner #: model:ir.model.fields,help:auth_partner.field_auth_partner__nbr_pending_reset_sent @@ -416,105 +453,109 @@ msgid "" "their password and you senddifferent mail depending on the number of " "reminder" msgstr "" +"Numero di reimpostazioni in sospeso inviate dal cliente. Questo campo è " +"utile quando, dopo una migrazione da un altro sistema, si chiede a tutti i " +"tuoi clienti di reimpostare la propria password e si inviano e-mail diverse " +"a seconda del numero di promemoria" #. module: auth_partner #: model:ir.actions.act_window,name:auth_partner.auth_partner_action #: model:ir.model.fields,field_description:auth_partner.field_auth_partner__partner_id #: model:ir.ui.menu,name:auth_partner.auth_partner_menu msgid "Partner" -msgstr "" +msgstr "Partner" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_res_partner__auth_partner_ids #: model:ir.model.fields,field_description:auth_partner.field_res_users__auth_partner_ids msgid "Partner Auth" -msgstr "" +msgstr "Autorizzazione partner" #. module: auth_partner #: model:ir.ui.menu,name:auth_partner.auth msgid "Partner Authentication" -msgstr "" +msgstr "Autenticazione partner" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_partner__password #: model:ir.model.fields,field_description:auth_partner.field_wizard_auth_partner_force_set_password__password msgid "Password" -msgstr "" +msgstr "Password" #. module: auth_partner #. odoo-python #: code:addons/auth_partner/wizards/wizard_auth_partner_force_set_password.py:0 #, python-format msgid "Password and Confirm Password must be the same" -msgstr "" +msgstr "La password e la conferma devono essere uguali" #. module: auth_partner #: model_terms:ir.ui.view,arch_db:auth_partner.auth_directory_view_form msgid "Regenerate secret key" -msgstr "" +msgstr "Rigenera chiave segreta" #. module: auth_partner #: model:mail.template,subject:auth_partner.email_reset_password msgid "Reset Password" -msgstr "" +msgstr "Resetta password" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__secret_key msgid "Secret Key" -msgstr "" +msgstr "Chiave segreta" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__secret_key_env_default msgid "Secret Key Env Default" -msgstr "" +msgstr "Chiave segreta ambiente predefinita" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__secret_key_env_is_editable msgid "Secret Key Env Is Editable" -msgstr "" +msgstr "La chiave segreta è modificabile" #. module: auth_partner #: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_form msgid "Send Invite" -msgstr "" +msgstr "Invia invito" #. module: auth_partner #: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_reset_password_view_form msgid "Send Reset Password" -msgstr "" +msgstr "Invia reset password" #. module: auth_partner #: model:ir.actions.act_window,name:auth_partner.auth_partner_action_reset_password msgid "Send Reset Password Instruction" -msgstr "" +msgstr "Invia istruzioni reset password" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__server_env_defaults msgid "Server Env Defaults" -msgstr "" +msgstr "Predefiniti ambiente server" #. module: auth_partner #: model:ir.actions.act_window,name:auth_partner.auth_partner_force_set_password_action #: model_terms:ir.ui.view,arch_db:auth_partner.auth_partner_view_form #: model_terms:ir.ui.view,arch_db:auth_partner.wizard_auth_partner_force_set_password_view_form msgid "Set Password" -msgstr "" +msgstr "Imposta password" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_directory__set_password_token_duration msgid "Set Password Token Duration" -msgstr "" +msgstr "Durata token impostazione password" #. module: auth_partner #: model:ir.model.fields,help:auth_partner.field_auth_partner__user_can_impersonate msgid "Technical field to check if the user can impersonate" -msgstr "" +msgstr "Campo tecnico per controllare se l'utente può imitare" #. module: auth_partner #: model:ir.model.fields,help:auth_partner.field_auth_directory__impersonating_user_ids #: model:ir.model.fields,help:auth_partner.field_auth_partner__impersonating_user_ids msgid "These odoo users can impersonate any partner of this directory" -msgstr "" +msgstr "Questi utenti Odoo possono imitare qualsiasi partner in questa cartella" #. module: auth_partner #: model:ir.model.fields,help:auth_partner.field_auth_partner__mail_verified @@ -522,34 +563,36 @@ msgid "" "This field is set to True when the user has clicked on the link sent by " "email" msgstr "" +"Questo campo è impostato a true quando l'utente ha cliccato nel collegamento " +"inviato per e-mail" #. module: auth_partner #. odoo-python #: code:addons/auth_partner/wizards/wizard_auth_partner_force_set_password.py:0 #, python-format msgid "This wizard can only be used on auth.partner" -msgstr "" +msgstr "Questa procedura guidata può essere usata solo su auth.partner" #. module: auth_partner #: model:ir.model.fields,field_description:auth_partner.field_auth_partner__user_can_impersonate msgid "User Can Impersonate" -msgstr "" +msgstr "L'utente può imitare" #. module: auth_partner #: model:mail.template,subject:auth_partner.email_set_password #: model:mail.template,subject:auth_partner.email_validate_email msgid "Welcome" -msgstr "" +msgstr "Benvenuto" #. module: auth_partner #: model:ir.model,name:auth_partner.model_wizard_auth_partner_force_set_password #: model:ir.model,name:auth_partner.model_wizard_auth_partner_reset_password msgid "Wizard Partner Auth Reset Password" -msgstr "" +msgstr "Procedura guidata reset password autorizzazione partner" #. module: auth_partner #. odoo-python #: code:addons/auth_partner/models/auth_partner.py:0 #, python-format msgid "You are not allowed to impersonate this user" -msgstr "" +msgstr "Non si è autorizzati a imitare questo utente" From 6b056fa27d9c31b33fae58c653a1127a5594d154 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Tue, 13 Jan 2026 11:16:48 +0100 Subject: [PATCH 6/8] [IMP] auth_partner: pre-commit auto fixes --- auth_partner/README.rst | 59 ++++++++++--------- auth_partner/data/email_data.xml | 25 ++++---- auth_partner/pyproject.toml | 3 + auth_partner/readme/CONTRIBUTORS.md | 3 + auth_partner/readme/CONTRIBUTORS.rst | 4 -- auth_partner/readme/DESCRIPTION.md | 19 ++++++ auth_partner/readme/DESCRIPTION.rst | 12 ---- auth_partner/readme/USAGE.md | 8 +++ auth_partner/readme/USAGE.rst | 8 --- auth_partner/static/description/index.html | 58 +++++++++--------- ...d_auth_partner_force_set_password_view.xml | 3 - ...izard_auth_partner_reset_password_view.xml | 32 +++++----- requirements.txt | 1 + 13 files changed, 122 insertions(+), 113 deletions(-) create mode 100644 auth_partner/pyproject.toml create mode 100644 auth_partner/readme/CONTRIBUTORS.md delete mode 100644 auth_partner/readme/CONTRIBUTORS.rst create mode 100644 auth_partner/readme/DESCRIPTION.md delete mode 100644 auth_partner/readme/DESCRIPTION.rst create mode 100644 auth_partner/readme/USAGE.md delete mode 100644 auth_partner/readme/USAGE.rst diff --git a/auth_partner/README.rst b/auth_partner/README.rst index 6f646f298..c0d848686 100644 --- a/auth_partner/README.rst +++ b/auth_partner/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 - ============ Partner Auth ============ @@ -17,33 +13,40 @@ Partner Auth .. |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%2Frest--framework-lightgray.png?logo=github - :target: https://github.com/OCA/rest-framework/tree/16.0/auth_partner + :target: https://github.com/OCA/rest-framework/tree/18.0/auth_partner :alt: OCA/rest-framework .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/rest-framework-16-0/rest-framework-16-0-auth_partner + :target: https://translation.odoo-community.org/projects/rest-framework-18-0/rest-framework-18-0-auth_partner :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/rest-framework&target_branch=16.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/rest-framework&target_branch=18.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| -This module adds to the partners the ability to authenticate through directories. +This module adds to the partners the ability to authenticate through +directories. -This module does not implement any routing, it only provides the basic mechanisms in a directory for: +This module does not implement any routing, it only provides the basic +mechanisms in a directory for: - - Registering a partner and sending an welcome email (to validate email address): `_signup` - - Authenticating a partner: `_login` - - Validating a partner email using a token: `_validate_email` - - Impersonating: `_impersonate`, `_impersonating` - - Resetting the password with a unique token sent by mail: `_request_reset_password`, `_set_password` - - Sending an invite mail when registering a partner from odoo interface for the partner to enter a password: `_send_invite`, `_set_password` - -For a routing implementation, see the `fastapi_auth_partner <../fastapi_auth_partner>`_ module. + - Registering a partner and sending an welcome email (to validate + email address): \_signup + - Authenticating a partner: \_login + - Validating a partner email using a token: \_validate_email + - Impersonating: \_impersonate, \_impersonating + - Resetting the password with a unique token sent by mail: + \_request_reset_password, \_set_password + - Sending an invite mail when registering a partner from odoo + interface for the partner to enter a password: \_send_invite, + \_set_password + +For a routing implementation, see the +`fastapi_auth_partner <../fastapi_auth_partner>`__ module. **Table of contents** @@ -53,7 +56,8 @@ For a routing implementation, see the `fastapi_auth_partner <../fastapi_auth_par Usage ===== -This module isn't meant to be used standalone but you can still see the directories and authenticable partners in: +This module isn't meant to be used standalone but you can still see the +directories and authenticable partners in: Settings > Technical > Partner Authentication > Partner @@ -61,14 +65,13 @@ and Settings > Technical > Partner Authentication > Directory - 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. @@ -76,20 +79,20 @@ Credits ======= Authors -~~~~~~~ +------- * Akretion Contributors -~~~~~~~~~~~~ +------------ -* `Akretion `_: +- `Akretion `__: - * Sébastien Beau - * Florian Mounier + - Sébastien Beau + - Florian Mounier Maintainers -~~~~~~~~~~~ +----------- This module is maintained by the OCA. @@ -101,6 +104,6 @@ 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. -This module is part of the `OCA/rest-framework `_ project on GitHub. +This module is part of the `OCA/rest-framework `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/auth_partner/data/email_data.xml b/auth_partner/data/email_data.xml index 92193d06d..ec7461f07 100644 --- a/auth_partner/data/email_data.xml +++ b/auth_partner/data/email_data.xml @@ -13,10 +13,10 @@ Hi Click on the following link to reset your password Reset Password + t-attf-href="https://example.org/password/reset?token={{ object.env.context['token']}}" + target="_blank" + style="color:#FFFFFF; text-decoration:none;" + >Reset Password @@ -35,10 +35,10 @@ Welcome, your account have been created Click on the following link to set your password Set Password + t-attf-href="https://example.org/password/reset?token={{ object.env.context['token']}}" + target="_blank" + style="color:#FFFFFF; text-decoration:none;" + >Set Password @@ -56,12 +56,11 @@ Hi Welcome to the site, please click on the following link to verify your email Validate Email + t-attf-href="https://example.org/email/validate?token={{ object.env.context['token']}}" + target="_blank" + style="color:#FFFFFF; text-decoration:none;" + >Validate Email - diff --git a/auth_partner/pyproject.toml b/auth_partner/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/auth_partner/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/auth_partner/readme/CONTRIBUTORS.md b/auth_partner/readme/CONTRIBUTORS.md new file mode 100644 index 000000000..6079ca504 --- /dev/null +++ b/auth_partner/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +- [Akretion](https://www.akretion.com): + - Sébastien Beau + - Florian Mounier diff --git a/auth_partner/readme/CONTRIBUTORS.rst b/auth_partner/readme/CONTRIBUTORS.rst deleted file mode 100644 index bae3cc9a1..000000000 --- a/auth_partner/readme/CONTRIBUTORS.rst +++ /dev/null @@ -1,4 +0,0 @@ -* `Akretion `_: - - * Sébastien Beau - * Florian Mounier diff --git a/auth_partner/readme/DESCRIPTION.md b/auth_partner/readme/DESCRIPTION.md new file mode 100644 index 000000000..71610a4cb --- /dev/null +++ b/auth_partner/readme/DESCRIPTION.md @@ -0,0 +1,19 @@ +This module adds to the partners the ability to authenticate through +directories. + +This module does not implement any routing, it only provides the basic +mechanisms in a directory for: + +> - Registering a partner and sending an welcome email (to validate +> email address): \_signup +> - Authenticating a partner: \_login +> - Validating a partner email using a token: \_validate_email +> - Impersonating: \_impersonate, \_impersonating +> - Resetting the password with a unique token sent by mail: +> \_request_reset_password, \_set_password +> - Sending an invite mail when registering a partner from odoo +> interface for the partner to enter a password: \_send_invite, +> \_set_password + +For a routing implementation, see the +[fastapi_auth_partner](../fastapi_auth_partner) module. diff --git a/auth_partner/readme/DESCRIPTION.rst b/auth_partner/readme/DESCRIPTION.rst deleted file mode 100644 index 2a63b69ea..000000000 --- a/auth_partner/readme/DESCRIPTION.rst +++ /dev/null @@ -1,12 +0,0 @@ -This module adds to the partners the ability to authenticate through directories. - -This module does not implement any routing, it only provides the basic mechanisms in a directory for: - - - Registering a partner and sending an welcome email (to validate email address): `_signup` - - Authenticating a partner: `_login` - - Validating a partner email using a token: `_validate_email` - - Impersonating: `_impersonate`, `_impersonating` - - Resetting the password with a unique token sent by mail: `_request_reset_password`, `_set_password` - - Sending an invite mail when registering a partner from odoo interface for the partner to enter a password: `_send_invite`, `_set_password` - -For a routing implementation, see the `fastapi_auth_partner <../fastapi_auth_partner>`_ module. diff --git a/auth_partner/readme/USAGE.md b/auth_partner/readme/USAGE.md new file mode 100644 index 000000000..455106eb3 --- /dev/null +++ b/auth_partner/readme/USAGE.md @@ -0,0 +1,8 @@ +This module isn't meant to be used standalone but you can still see the +directories and authenticable partners in: + +Settings \> Technical \> Partner Authentication \> Partner + +and + +Settings \> Technical \> Partner Authentication \> Directory diff --git a/auth_partner/readme/USAGE.rst b/auth_partner/readme/USAGE.rst deleted file mode 100644 index 39cb46f62..000000000 --- a/auth_partner/readme/USAGE.rst +++ /dev/null @@ -1,8 +0,0 @@ -This module isn't meant to be used standalone but you can still see the directories and authenticable partners in: - -Settings > Technical > Partner Authentication > Partner - -and - -Settings > Technical > Partner Authentication > Directory - diff --git a/auth_partner/static/description/index.html b/auth_partner/static/description/index.html index fe776ea15..eb1137e3b 100644 --- a/auth_partner/static/description/index.html +++ b/auth_partner/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +Partner Auth -
+
+

Partner Auth

- - -Odoo Community Association - -
-

Partner Auth

-

Beta License: AGPL-3 OCA/rest-framework Translate me on Weblate Try me on Runboat

-

This module adds to the partners the ability to authenticate through directories.

-

This module does not implement any routing, it only provides the basic mechanisms in a directory for:

+

Beta License: AGPL-3 OCA/rest-framework Translate me on Weblate Try me on Runboat

+

This module adds to the partners the ability to authenticate through +directories.

+

This module does not implement any routing, it only provides the basic +mechanisms in a directory for:

    -
  • Registering a partner and sending an welcome email (to validate email address): _signup
  • -
  • Authenticating a partner: _login
  • -
  • Validating a partner email using a token: _validate_email
  • -
  • Impersonating: _impersonate, _impersonating
  • -
  • Resetting the password with a unique token sent by mail: _request_reset_password, _set_password
  • -
  • Sending an invite mail when registering a partner from odoo interface for the partner to enter a password: _send_invite, _set_password
  • +
  • Registering a partner and sending an welcome email (to validate +email address): _signup
  • +
  • Authenticating a partner: _login
  • +
  • Validating a partner email using a token: _validate_email
  • +
  • Impersonating: _impersonate, _impersonating
  • +
  • Resetting the password with a unique token sent by mail: +_request_reset_password, _set_password
  • +
  • Sending an invite mail when registering a partner from odoo +interface for the partner to enter a password: _send_invite, +_set_password
-

For a routing implementation, see the fastapi_auth_partner module.

+

For a routing implementation, see the +fastapi_auth_partner module.

Table of contents

    @@ -402,30 +404,31 @@

    Partner Auth

-

Usage

-

This module isn’t meant to be used standalone but you can still see the directories and authenticable partners in:

+

Usage

+

This module isn’t meant to be used standalone but you can still see the +directories and authenticable partners in:

Settings > Technical > Partner Authentication > Partner

and

Settings > Technical > Partner Authentication > Directory

-

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
-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -443,11 +446,10 @@

Maintainers

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.

-

This module is part of the OCA/rest-framework project on GitHub.

+

This module is part of the OCA/rest-framework project on GitHub.

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

-
diff --git a/auth_partner/wizards/wizard_auth_partner_force_set_password_view.xml b/auth_partner/wizards/wizard_auth_partner_force_set_password_view.xml index 8742520c5..e83a5e13e 100644 --- a/auth_partner/wizards/wizard_auth_partner_force_set_password_view.xml +++ b/auth_partner/wizards/wizard_auth_partner_force_set_password_view.xml @@ -5,7 +5,6 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> - wizard.auth.partner.force.set.password @@ -23,7 +22,6 @@ />
@@ -77,7 +81,7 @@ Directory ir.actions.act_window auth.directory - tree,form + list,form [] {} diff --git a/auth_partner/views/auth_partner_view.xml b/auth_partner/views/auth_partner_view.xml index bc9459442..b0bb45977 100644 --- a/auth_partner/views/auth_partner_view.xml +++ b/auth_partner/views/auth_partner_view.xml @@ -3,7 +3,7 @@ auth.partner - + @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ type="object" string="Impersonate" class="btn-info" - attrs="{'invisible': [('user_can_impersonate', '=', False)]}" + invisible="not user_can_impersonate" />
diff --git a/auth_partner/wizards/wizard_auth_partner_force_set_password.py b/auth_partner/wizards/wizard_auth_partner_force_set_password.py index 66952d3bb..3e0c8b18c 100644 --- a/auth_partner/wizards/wizard_auth_partner_force_set_password.py +++ b/auth_partner/wizards/wizard_auth_partner_force_set_password.py @@ -3,7 +3,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import _, api, fields, models +from odoo import api, fields, models from odoo.exceptions import UserError, ValidationError @@ -19,16 +19,14 @@ def _check_password(self): for wizard in self: if wizard.password != wizard.password_confirm: raise ValidationError( - _("Password and Confirm Password must be the same") + self.env._("Password and Confirm Password must be the same") ) def action_force_set_password(self): self.ensure_one() - if self.env.context.get("active_model") != "auth.partner": - raise UserError(_("This wizard can only be used on auth.partner")) - auth_partner_id = self.env.context.get("active_id") + auth_partner_id = self.env.context.get("id") if not auth_partner_id: - raise UserError(_("No active_id in context")) + raise UserError(self.env._("No id in context")) auth_partner = self.env["auth.partner"].browse(auth_partner_id) diff --git a/auth_partner/wizards/wizard_auth_partner_reset_password_view.xml b/auth_partner/wizards/wizard_auth_partner_reset_password_view.xml index 48b734676..4fafa5574 100644 --- a/auth_partner/wizards/wizard_auth_partner_reset_password_view.xml +++ b/auth_partner/wizards/wizard_auth_partner_reset_password_view.xml @@ -10,8 +10,8 @@