mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[ADD] pms_api_rest: module created
This commit is contained in:
committed by
Darío Lodeiros
parent
02f8f126ca
commit
75f453adec
5
pms_api_rest/__init__.py
Normal file
5
pms_api_rest/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from . import controllers
|
||||||
|
from . import datamodels
|
||||||
|
from . import models
|
||||||
|
from . import services
|
||||||
|
|
||||||
19
pms_api_rest/__manifest__.py
Normal file
19
pms_api_rest/__manifest__.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "API REST PMS",
|
||||||
|
"author": "Commit [Sun], Odoo Community Association (OCA)",
|
||||||
|
"website": "https://github.com/OCA/pms",
|
||||||
|
"category": "Generic Modules/Property Management System",
|
||||||
|
"version": "14.0.1.0.0",
|
||||||
|
"license": "AGPL-3",
|
||||||
|
"depends": [
|
||||||
|
"pms",
|
||||||
|
"base_rest",
|
||||||
|
"base_rest_datamodel",
|
||||||
|
"web",
|
||||||
|
"auth_signup",
|
||||||
|
],
|
||||||
|
"external_dependencies": {
|
||||||
|
"python": ["jwt", "simplejson", "marshmallow"],
|
||||||
|
},
|
||||||
|
"installable": True,
|
||||||
|
}
|
||||||
2
pms_api_rest/controllers/__init__.py
Normal file
2
pms_api_rest/controllers/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
from . import jwt_controller
|
||||||
|
from . import pms_rest
|
||||||
110
pms_api_rest/controllers/jwt_controller.py
Normal file
110
pms_api_rest/controllers/jwt_controller.py
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
import werkzeug
|
||||||
|
|
||||||
|
from odoo import http
|
||||||
|
from odoo.http import request
|
||||||
|
|
||||||
|
from odoo.addons.auth_signup.models.res_users import SignupError
|
||||||
|
|
||||||
|
from ..lib.jwt_http import jwt_http
|
||||||
|
from ..lib.validator import validator
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
SENSITIVE_FIELDS = [
|
||||||
|
"password",
|
||||||
|
"password_crypt",
|
||||||
|
"new_password",
|
||||||
|
"create_uid",
|
||||||
|
"write_uid",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class JwtController(http.Controller):
|
||||||
|
# test route
|
||||||
|
@http.route("/api/info", auth="public", csrf=False, cors="*")
|
||||||
|
def index(self, **kw):
|
||||||
|
return "Hello, world"
|
||||||
|
|
||||||
|
@http.route(
|
||||||
|
"/api/login", type="http", auth="public", csrf=False, cors="*", methods=["POST"]
|
||||||
|
)
|
||||||
|
def login(self, email, password, **kw):
|
||||||
|
return jwt_http.do_login(email, password)
|
||||||
|
|
||||||
|
@http.route("/api/me", type="http", auth="public", csrf=False, cors="*")
|
||||||
|
def me(self, **kw):
|
||||||
|
http_method, body, headers, token = jwt_http.parse_request()
|
||||||
|
result = validator.verify_token(token)
|
||||||
|
if not result["status"]:
|
||||||
|
return jwt_http.errcode(code=result["code"], message=result["message"])
|
||||||
|
|
||||||
|
return jwt_http.response(request.env.user.to_dict(True))
|
||||||
|
|
||||||
|
@http.route("/api/logout", type="http", auth="public", csrf=False, cors="*")
|
||||||
|
def logout(self, **kw):
|
||||||
|
http_method, body, headers, token = jwt_http.parse_request()
|
||||||
|
result = validator.verify_token(token)
|
||||||
|
if not result["status"]:
|
||||||
|
return jwt_http.errcode(code=result["code"], message=result["message"])
|
||||||
|
|
||||||
|
jwt_http.do_logout(token)
|
||||||
|
return jwt_http.response()
|
||||||
|
|
||||||
|
@http.route(
|
||||||
|
"/api/register",
|
||||||
|
type="http",
|
||||||
|
auth="public",
|
||||||
|
csrf=False,
|
||||||
|
cors="*",
|
||||||
|
methods=["POST"],
|
||||||
|
)
|
||||||
|
def register(self, email=None, name=None, password=None, **kw):
|
||||||
|
if not validator.is_valid_email(email):
|
||||||
|
return jwt_http.errcode(code=400, message="Invalid email address")
|
||||||
|
if not name:
|
||||||
|
return jwt_http.errcode(code=400, message="Name cannot be empty")
|
||||||
|
if not password:
|
||||||
|
return jwt_http.errcode(code=400, message="Password cannot be empty")
|
||||||
|
|
||||||
|
# sign up
|
||||||
|
try:
|
||||||
|
self._signup_with_values(login=email, name=name, password=password)
|
||||||
|
except AttributeError:
|
||||||
|
return jwt_http.errcode(code=501, message="Signup is disabled")
|
||||||
|
except (SignupError, AssertionError) as e:
|
||||||
|
if request.env["res.users"].sudo().search([("login", "=", email)]):
|
||||||
|
return jwt_http.errcode(
|
||||||
|
code=400, message="Email address already exists"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
_logger.error("%s", e)
|
||||||
|
return jwt_http.response_500()
|
||||||
|
except Exception as e:
|
||||||
|
_logger.error(str(e))
|
||||||
|
return jwt_http.response_500()
|
||||||
|
# log the user in
|
||||||
|
return jwt_http.do_login(email, password)
|
||||||
|
|
||||||
|
def _signup_with_values(self, **values):
|
||||||
|
request.env["res.users"].sudo().signup(values, None)
|
||||||
|
request.env.cr.commit() # as authenticate will use its
|
||||||
|
# own cursor we need to commit the current transaction
|
||||||
|
self.signup_email(values)
|
||||||
|
|
||||||
|
def signup_email(self, values):
|
||||||
|
user_sudo = (
|
||||||
|
request.env["res.users"]
|
||||||
|
.sudo()
|
||||||
|
.search([("login", "=", values.get("login"))])
|
||||||
|
)
|
||||||
|
template = request.env.ref(
|
||||||
|
"auth_signup.mail_template_user_signup_account_created",
|
||||||
|
raise_if_not_found=False,
|
||||||
|
)
|
||||||
|
if user_sudo and template:
|
||||||
|
template.sudo().with_context(
|
||||||
|
lang=user_sudo.lang,
|
||||||
|
auth_login=werkzeug.url_encode({"auth_login": user_sudo.email}),
|
||||||
|
).send_mail(user_sudo.id, force_send=True)
|
||||||
22
pms_api_rest/controllers/pms_rest.py
Normal file
22
pms_api_rest/controllers/pms_rest.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
from odoo.addons.base_rest.controllers import main
|
||||||
|
|
||||||
|
from ..lib.jwt_http import jwt_http
|
||||||
|
from ..lib.validator import validator
|
||||||
|
|
||||||
|
|
||||||
|
class BaseRestDemoPublicApiController(main.RestController):
|
||||||
|
_root_path = "/api/"
|
||||||
|
_collection_name = "pms.reservation.service"
|
||||||
|
_default_auth = "public"
|
||||||
|
|
||||||
|
# RestController OVERRIDE method
|
||||||
|
def _process_method(self, service_name, method_name, *args, params=None):
|
||||||
|
|
||||||
|
http_method, body, headers, token = jwt_http.parse_request()
|
||||||
|
result = validator.verify_token(token)
|
||||||
|
if not result["status"]:
|
||||||
|
return jwt_http.errcode(code=result["code"], message=result["message"])
|
||||||
|
else:
|
||||||
|
return super(BaseRestDemoPublicApiController, self)._process_method(
|
||||||
|
service_name, method_name, *args, params=params
|
||||||
|
)
|
||||||
2
pms_api_rest/datamodels/__init__.py
Normal file
2
pms_api_rest/datamodels/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
from . import pms_reservation_short_info
|
||||||
|
from . import pms_reservation_search_param
|
||||||
10
pms_api_rest/datamodels/pms_reservation_search_param.py
Normal file
10
pms_api_rest/datamodels/pms_reservation_search_param.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from marshmallow import fields
|
||||||
|
|
||||||
|
from odoo.addons.datamodel.core import Datamodel
|
||||||
|
|
||||||
|
|
||||||
|
class PmsReservationSearchParam(Datamodel):
|
||||||
|
_name = "pms.reservation.search.param"
|
||||||
|
|
||||||
|
id = fields.Integer(required=False, allow_none=False)
|
||||||
|
name = fields.String(required=False, allow_none=False)
|
||||||
16
pms_api_rest/datamodels/pms_reservation_short_info.py
Normal file
16
pms_api_rest/datamodels/pms_reservation_short_info.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from marshmallow import fields
|
||||||
|
|
||||||
|
from odoo.addons.datamodel.core import Datamodel
|
||||||
|
|
||||||
|
|
||||||
|
class PmsReservationShortInfo(Datamodel):
|
||||||
|
_name = "pms.reservation.short.info"
|
||||||
|
|
||||||
|
id = fields.Integer(required=True, allow_none=False)
|
||||||
|
partner = fields.String(required=True, allow_none=False)
|
||||||
|
checkin = fields.String(required=True, allow_none=False)
|
||||||
|
checkout = fields.String(required=True, allow_none=False)
|
||||||
|
preferred_room_id = fields.String(required=True, allow_none=False)
|
||||||
|
room_type_id = fields.String(required=True, allow_none=False)
|
||||||
|
name = fields.String(required=True, allow_none=False)
|
||||||
|
partner_requests = fields.String(required=False, allow_none=True)
|
||||||
2
pms_api_rest/models/__init__.py
Normal file
2
pms_api_rest/models/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
from . import res_users
|
||||||
|
from . import jwt_access_token
|
||||||
32
pms_api_rest/models/jwt_access_token.py
Normal file
32
pms_api_rest/models/jwt_access_token.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from odoo import api, fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class JwtAccessToken(models.Model):
|
||||||
|
_name = "jwt_provider.access_token"
|
||||||
|
_description = "Store user access token for one-time-login"
|
||||||
|
|
||||||
|
token = fields.Char(
|
||||||
|
"Access Token",
|
||||||
|
required=True
|
||||||
|
)
|
||||||
|
user_id = fields.Many2one(
|
||||||
|
comodel_name="res.users",
|
||||||
|
string="User",
|
||||||
|
required=True,
|
||||||
|
ondelete="cascade",
|
||||||
|
)
|
||||||
|
expires = fields.Datetime(
|
||||||
|
"Expires",
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
is_expired = fields.Boolean(
|
||||||
|
compute="_compute_is_expired",
|
||||||
|
)
|
||||||
|
|
||||||
|
@api.depends("expires")
|
||||||
|
def _compute_is_expired(self):
|
||||||
|
for token in self:
|
||||||
|
token.is_expired = datetime.now() > token.expires
|
||||||
43
pms_api_rest/models/res_users.py
Normal file
43
pms_api_rest/models/res_users.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from odoo import _, api, fields, models
|
||||||
|
from odoo.exceptions import AccessDenied, ValidationError
|
||||||
|
|
||||||
|
from ..lib.validator import validator
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class ResUsers(models.Model):
|
||||||
|
_inherit = "res.users"
|
||||||
|
|
||||||
|
access_token_ids = fields.One2many(
|
||||||
|
string="Access Tokens",
|
||||||
|
comodel_name="jwt_provider.access_token",
|
||||||
|
inverse_name="user_id",
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _login(cls, db, login, password, user_agent_env):
|
||||||
|
user_id = super(ResUsers, cls)._login(db, login, password, user_agent_env)
|
||||||
|
if user_id:
|
||||||
|
return user_id
|
||||||
|
uid = validator.verify(password)
|
||||||
|
_logger.info(uid)
|
||||||
|
return uid
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _check_credentials(self, password, user_agent_env):
|
||||||
|
try:
|
||||||
|
super(ResUsers, self)._check_credentials(password, user_agent_env)
|
||||||
|
except AccessDenied:
|
||||||
|
if not validator.verify(password):
|
||||||
|
raise
|
||||||
|
|
||||||
|
def to_dict(self, single=False):
|
||||||
|
res = []
|
||||||
|
for u in self:
|
||||||
|
d = u.read(["email", "name", "company_id"])[0]
|
||||||
|
res.append(d)
|
||||||
|
|
||||||
|
return res[0] if single else res
|
||||||
2
pms_api_rest/security/ir.model.access.csv
Normal file
2
pms_api_rest/security/ir.model.access.csv
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
|
access_jwt_access_token,Read jwt access token,model_jwt_provider_access_token,,1,0,0,0
|
||||||
|
1
pms_api_rest/services/__init__.py
Normal file
1
pms_api_rest/services/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from . import reservation_services
|
||||||
51
pms_api_rest/services/reservation_services.py
Normal file
51
pms_api_rest/services/reservation_services.py
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
from odoo.addons.base_rest import restapi
|
||||||
|
from odoo.addons.base_rest_datamodel.restapi import Datamodel
|
||||||
|
from odoo.addons.component.core import Component
|
||||||
|
|
||||||
|
|
||||||
|
class PmsReservationService(Component):
|
||||||
|
_inherit = "base.rest.service"
|
||||||
|
_name = "pms.reservation.service"
|
||||||
|
_usage = "reservations"
|
||||||
|
_collection = "pms.reservation.service"
|
||||||
|
|
||||||
|
@restapi.method(
|
||||||
|
[
|
||||||
|
(
|
||||||
|
[
|
||||||
|
"/",
|
||||||
|
],
|
||||||
|
"GET"
|
||||||
|
)
|
||||||
|
],
|
||||||
|
input_param=Datamodel("pms.reservation.search.param"),
|
||||||
|
output_param=Datamodel("pms.reservation.short.info", is_list=True),
|
||||||
|
auth="public",
|
||||||
|
)
|
||||||
|
def search(self, reservation_search_param):
|
||||||
|
domain = []
|
||||||
|
if reservation_search_param.name:
|
||||||
|
domain.append(("name", "like", reservation_search_param.name))
|
||||||
|
if reservation_search_param.id:
|
||||||
|
domain.append(("id", "=", reservation_search_param.id))
|
||||||
|
res = []
|
||||||
|
PmsReservationShortInfo = self.env.datamodels["pms.reservation.short.info"]
|
||||||
|
for reservation in self.env["pms.reservation"].sudo().search(
|
||||||
|
domain,
|
||||||
|
):
|
||||||
|
res.append(
|
||||||
|
PmsReservationShortInfo(
|
||||||
|
id=reservation.id,
|
||||||
|
partner=reservation.partner_id.name,
|
||||||
|
checkin=str(reservation.checkin),
|
||||||
|
checkout=str(reservation.checkout),
|
||||||
|
preferred_room_id=reservation.preferred_room_id.name
|
||||||
|
if reservation.preferred_room_id
|
||||||
|
else "",
|
||||||
|
room_type_id=reservation.room_type_id.name
|
||||||
|
if reservation.room_type_id
|
||||||
|
else "",
|
||||||
|
name=reservation.name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return res
|
||||||
BIN
pms_api_rest/static/description/icon.png
Normal file
BIN
pms_api_rest/static/description/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
Reference in New Issue
Block a user