-
-
Notifications
You must be signed in to change notification settings - Fork 309
/
Copy pathdependencies.py
171 lines (135 loc) · 6.09 KB
/
dependencies.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# Copyright 2022 ACSONE SA/NV
# License LGPL-3.0 or later (http://www.gnu.org/licenses/LGPL).
from typing import TYPE_CHECKING, Annotated
from odoo.api import Environment
from odoo.exceptions import AccessDenied
from odoo.addons.base.models.res_partner import Partner
from odoo.addons.base.models.res_users import Users
from fastapi import Depends, Header, HTTPException, Query, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from .context import odoo_env_ctx
from .schemas import Paging
if TYPE_CHECKING:
from .models.fastapi_endpoint import FastapiEndpoint
def company_id() -> int | None:
"""This method may be overriden by the FastAPI app to set the allowed company
in the Odoo env of the endpoint. By default, the company defined on the
endpoint record is used.
"""
return None
def odoo_env(company_id: Annotated[int | None, Depends(company_id)]) -> Environment:
env = odoo_env_ctx.get()
if company_id is not None:
env = env(context=dict(env.context, allowed_company_ids=[company_id]))
yield env
def authenticated_partner_impl() -> Partner:
"""This method has to be overriden when you create your fastapi app
to declare the way your partner will be provided. In some case, this
partner will come from the authentication mechanism (ex jwt token) in other cases
it could comme from a lookup on an email received into an HTTP header ...
See the fastapi_endpoint_demo for an example"""
def optionally_authenticated_partner_impl() -> Partner | None:
"""This method has to be overriden when you create your fastapi app
and you need to get an optional authenticated partner into your endpoint.
"""
def authenticated_partner_env(
partner: Annotated[Partner, Depends(authenticated_partner_impl)]
) -> Environment:
"""Return an environment with the authenticated partner id in the context"""
return partner.with_context(authenticated_partner_id=partner.id).env
def optionally_authenticated_partner_env(
partner: Annotated[Partner | None, Depends(optionally_authenticated_partner_impl)],
env: Annotated[Environment, Depends(odoo_env)],
) -> Environment:
"""Return an environment with the authenticated partner id in the context if
the partner is not None
"""
if partner:
return partner.with_context(authenticated_partner_id=partner.id).env
return env
def authenticated_partner(
partner: Annotated[Partner, Depends(authenticated_partner_impl)],
partner_env: Annotated[Environment, Depends(authenticated_partner_env)],
) -> Partner:
"""If you need to get access to the authenticated partner into your
endpoint, you can add a dependency into the endpoint definition on this
method.
This method is a safe way to declare a dependency without requiring a
specific implementation. It depends on `authenticated_partner_impl`. The
concrete implementation of authenticated_partner_impl has to be provided
when the FastAPI app is created.
This method return a partner into the authenticated_partner_env
"""
return partner_env["res.partner"].browse(partner.id)
def optionally_authenticated_partner(
partner: Annotated[Partner | None, Depends(optionally_authenticated_partner_impl)],
partner_env: Annotated[Environment, Depends(optionally_authenticated_partner_env)],
) -> Partner | None:
"""If you need to get access to the authenticated partner if the call is
authenticated, you can add a dependency into the endpoint definition on this
method.
This method defer from authenticated_partner by the fact that it returns
None if the partner is not authenticated .
"""
if partner:
return partner_env["res.partner"].browse(partner.id)
return None
def paging(
page: Annotated[int, Query(ge=1)] = 1, page_size: Annotated[int, Query(ge=1)] = 80
) -> Paging:
"""Return a Paging object from the page and page_size parameters"""
return Paging(limit=page_size, offset=(page - 1) * page_size)
def basic_auth_user(
credential: Annotated[HTTPBasicCredentials, Depends(HTTPBasic())],
env: Annotated[Environment, Depends(odoo_env)],
) -> Users:
username = credential.username
password = credential.password
try:
uid = (
env["res.users"]
.sudo()
.authenticate(
db=env.cr.dbname, login=username, password=password, user_agent_env=None
)
)
return env["res.users"].browse(uid)
except AccessDenied as ad:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Basic"},
) from ad
def authenticated_partner_from_basic_auth_user(
user: Annotated[Users, Depends(basic_auth_user)],
env: Annotated[Environment, Depends(odoo_env)],
) -> Partner:
return env["res.partner"].browse(user.sudo().partner_id.id)
def fastapi_endpoint_id() -> int:
"""This method is overriden by the FastAPI app to make the fastapi.endpoint record
available for your endpoint method. To get the fastapi.endpoint record
in your method, you just need to add a dependency on the fastapi_endpoint method
defined below
"""
def fastapi_endpoint(
_id: Annotated[int, Depends(fastapi_endpoint_id)],
env: Annotated[Environment, Depends(odoo_env)],
) -> "FastapiEndpoint":
"""Return the fastapi.endpoint record"""
return env["fastapi.endpoint"].browse(_id)
def accept_language(
accept_language: Annotated[
str | None,
Header(
alias="Accept-Language",
description="The Accept-Language header is used to specify the language "
"of the content to be returned. If a language is not available, the "
"server will return the content in the default language.",
),
] = None,
) -> str:
"""This dependency is used at application level to document the way the language
to use for the response is specified. The header is processed outside of the
fastapi app to initialize the odoo environment with the right language.
"""
return accept_language