-
-
Notifications
You must be signed in to change notification settings - Fork 82
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
63340f8
commit 111664b
Showing
18 changed files
with
639 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from . import controllers | ||
from . import datamodels | ||
from . import models | ||
from . import services | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from . import jwt_controller | ||
from . import pms_rest |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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.jwt_http import jwt_http | ||
from ..lib_jwt.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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
from odoo.addons.base_rest.controllers import main | ||
|
||
from ..lib_jwt.jwt_http import jwt_http | ||
from ..lib_jwt.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 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from . import pms_reservation_short_info | ||
from . import pms_reservation_search_param |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
import simplejson as json | ||
|
||
from odoo import http | ||
from odoo.exceptions import AccessDenied | ||
from odoo.http import Response, request | ||
|
||
from .validator import validator | ||
|
||
return_fields = ["id", "login", "name", "company_id"] | ||
|
||
|
||
class JwtHttp: | ||
def get_state(self): | ||
return {"d": request.session.db} | ||
|
||
def parse_request(self): | ||
http_method = request.httprequest.method | ||
try: | ||
body = http.request.params | ||
except Exception: | ||
body = {} | ||
|
||
headers = dict(list(request.httprequest.headers.items())) | ||
if "wsgi.input" in headers: | ||
del headers["wsgi.input"] | ||
if "wsgi.errors" in headers: | ||
del headers["wsgi.errors"] | ||
if "HTTP_AUTHORIZATION" in headers: | ||
headers["Authorization"] = headers["HTTP_AUTHORIZATION"] | ||
|
||
# extract token | ||
token = "" | ||
if "Authorization" in headers: | ||
try: | ||
# Bearer token_string | ||
token = headers["Authorization"].split(" ")[1] | ||
except Exception: | ||
pass | ||
|
||
return http_method, body, headers, token | ||
|
||
def date2str(self, d, f="%Y-%m-%d %H:%M:%S"): | ||
""" | ||
Convert datetime to string | ||
:param self: | ||
:param d: datetime object | ||
:param f='%Y-%m-%d%H:%M:%S': string format | ||
""" | ||
try: | ||
s = d.strftime(f) | ||
except Exception: | ||
s = None | ||
|
||
return s | ||
|
||
def response(self, success=True, message=None, data=None, code=200): | ||
""" | ||
Create a HTTP Response for controller | ||
:param success=True indicate this response is successful or not | ||
:param message=None message string | ||
:param data=None data to return | ||
:param code=200 http status code | ||
""" | ||
print('response') | ||
print('response') | ||
print('response') | ||
print('response') | ||
payload = json.dumps( | ||
{ | ||
"success": success, | ||
"message": message, | ||
"data": data, | ||
} | ||
) | ||
|
||
return Response( | ||
payload, | ||
status=code, | ||
headers=[ | ||
("Content-Type", "application/json"), | ||
], | ||
) | ||
|
||
def response_500(self, message="Internal Server Error", data=None): | ||
return self.response(success=False, message=message, data=data, code=500) | ||
|
||
def response_401(self, message="401 Unauthorized", data=None): | ||
return self.response(success=False, message=message, data=data, code=401) | ||
|
||
def response_404(self, message="404 Not Found", data=None): | ||
return self.response(success=False, message=message, data=data, code=404) | ||
|
||
def response_403(self, message="403 Forbidden", data=None): | ||
return self.response(success=False, message=message, data=data, code=403) | ||
|
||
def errcode(self, code, message=None): | ||
return self.response(success=False, code=code, message=message) | ||
|
||
def do_login(self, login, password): | ||
# get current db | ||
state = self.get_state() | ||
try: | ||
uid = request.session.authenticate(state["d"], login, password) | ||
except AccessDenied: | ||
return self.response_401() | ||
if not uid: | ||
return self.response_401() | ||
|
||
# login success, generate token | ||
user = request.env.user.read(return_fields)[0] | ||
token = validator.create_token(user) | ||
|
||
return self.response(data={"user": user, "token": token}) | ||
|
||
def do_logout(self, token): | ||
request.session.logout() | ||
request.env["jwt_provider.access_token"].sudo().search( | ||
[("token", "=", token)] | ||
).unlink() | ||
return self.response() | ||
|
||
def cleanup(self): | ||
# Clean up things after success request | ||
# use logout here to make request as stateless as possible | ||
request.session.logout() | ||
return self.response() | ||
|
||
|
||
jwt_http = JwtHttp() |
Oops, something went wrong.