Initial commit: OCA Technical packages (595 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:03 +02:00
commit 2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions

View file

@ -0,0 +1,209 @@
# Copyright 2024 Akretion (http://www.akretion.com).
# @author Sébastien BEAU <sebastien.beau@akretion.com>
# @author Florian Mounier <florian.mounier@akretion.com>
# 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": {}}