EnCoach Odoo 19 custom modules
Full backend implementation with custom Odoo modules: - encoach_api: Core API, user management, JWT auth - encoach_exam: Exam generation (reading, writing, listening, speaking) - encoach_evaluate: AI-powered evaluation (writing, speaking) - encoach_training: Training tips and walkthrough - encoach_storage: File storage management - encoach_payment: Stripe, PayPal, Paymob integration - encoach_mail: Email notifications Made-with: Cursor
This commit is contained in:
149
encoach_api/controllers/registration.py
Normal file
149
encoach_api/controllers/registration.py
Normal file
@@ -0,0 +1,149 @@
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import jwt as pyjwt
|
||||
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
|
||||
from .base import EncoachMixin
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RegistrationController(EncoachMixin, http.Controller):
|
||||
|
||||
@http.route('/api/register', type='http', auth='public', methods=['POST', 'OPTIONS'], csrf=False, cors='*')
|
||||
def register(self, **kwargs):
|
||||
try:
|
||||
body = self._get_json_body()
|
||||
email = body.get('email', '').strip()
|
||||
password = body.get('password', '')
|
||||
name = body.get('name', '').strip()
|
||||
user_type = body.get('type', 'student')
|
||||
|
||||
if not email or not password or not name:
|
||||
return self._error_response('name, email, and password are required', 400)
|
||||
|
||||
Users = request.env['res.users'].sudo()
|
||||
existing = Users.search([('login', '=', email)], limit=1)
|
||||
if existing:
|
||||
return self._error_response('A user with this email already exists', 409)
|
||||
|
||||
main_company = request.env['res.company'].sudo().search([], limit=1, order='id')
|
||||
vals = {
|
||||
'name': name,
|
||||
'login': email,
|
||||
'password': password,
|
||||
'encoach_type': user_type,
|
||||
'is_verified': False,
|
||||
'company_id': main_company.id,
|
||||
'company_ids': [(6, 0, [main_company.id])],
|
||||
}
|
||||
|
||||
code_str = body.get('code')
|
||||
if code_str:
|
||||
result = request.env['encoach.code'].sudo().validate_code(code_str)
|
||||
if result.get('valid'):
|
||||
code_rec = request.env['encoach.code'].sudo().search([('code', '=', code_str)], limit=1)
|
||||
if code_rec and code_rec.user_type:
|
||||
vals['encoach_type'] = code_rec.user_type
|
||||
|
||||
user = Users.create(vals)
|
||||
|
||||
if code_str:
|
||||
code_rec = request.env['encoach.code'].sudo().search([('code', '=', code_str)], limit=1)
|
||||
if code_rec:
|
||||
if code_rec.entity_id:
|
||||
request.env['encoach.user.entity.rel'].sudo().create({
|
||||
'user_id': user.id,
|
||||
'entity_id': code_rec.entity_id.id,
|
||||
})
|
||||
code_rec.sudo().write({'uses': code_rec.uses + 1})
|
||||
|
||||
secret = request.env['ir.config_parameter'].sudo().get_param('encoach.jwt_secret')
|
||||
token = pyjwt.encode({
|
||||
'user_id': user.id,
|
||||
'email': user.login,
|
||||
'iat': datetime.utcnow(),
|
||||
'exp': datetime.utcnow() + timedelta(hours=72),
|
||||
}, secret, algorithm='HS256')
|
||||
|
||||
return self._json_response({
|
||||
'user': self._serialize(user),
|
||||
'token': token,
|
||||
}, status=201)
|
||||
except Exception:
|
||||
_logger.exception("Registration error")
|
||||
return self._error_response('Internal server error', 500)
|
||||
|
||||
@http.route(
|
||||
'/api/code/<string:code>', type='http', auth='public',
|
||||
methods=['GET', 'OPTIONS'], csrf=False, cors='*',
|
||||
)
|
||||
def validate_code(self, code, **kwargs):
|
||||
try:
|
||||
result = request.env['encoach.code'].sudo().validate_code(code)
|
||||
if not result.get('valid'):
|
||||
return self._error_response(result.get('error', 'Invalid code'), 404)
|
||||
return self._json_response(result['code'])
|
||||
except Exception:
|
||||
_logger.exception("Validate code error")
|
||||
return self._error_response('Internal server error', 500)
|
||||
|
||||
@http.route('/api/batch_users', type='http', auth='public', methods=['POST', 'OPTIONS'], csrf=False, cors='*')
|
||||
def batch_users(self, **kwargs):
|
||||
try:
|
||||
user = self._authenticate()
|
||||
if not user:
|
||||
return self._error_response('Unauthorized', 401)
|
||||
|
||||
body = self._get_json_body()
|
||||
users_data = body.get('users', [])
|
||||
if not users_data:
|
||||
return self._error_response('users array is required', 400)
|
||||
|
||||
mixin = request.env['encoach.registration.mixin'].sudo()
|
||||
result = mixin.batch_import(users_data, user.id)
|
||||
return self._json_response(result)
|
||||
except Exception:
|
||||
_logger.exception("Batch users error")
|
||||
return self._error_response('Internal server error', 500)
|
||||
|
||||
@http.route('/api/make_user', type='http', auth='public', methods=['POST', 'OPTIONS'], csrf=False, cors='*')
|
||||
def make_user(self, **kwargs):
|
||||
try:
|
||||
user = self._authenticate()
|
||||
if not user:
|
||||
return self._error_response('Unauthorized', 401)
|
||||
|
||||
body = self._get_json_body()
|
||||
email = body.get('email', '').strip()
|
||||
name = body.get('name', '').strip()
|
||||
password = body.get('password', '')
|
||||
if not email or not name:
|
||||
return self._error_response('name and email are required', 400)
|
||||
|
||||
Users = request.env['res.users'].sudo()
|
||||
existing = Users.search([('login', '=', email)], limit=1)
|
||||
if existing:
|
||||
return self._error_response('A user with this email already exists', 409)
|
||||
|
||||
import secrets
|
||||
if not password:
|
||||
password = secrets.token_urlsafe(12)
|
||||
|
||||
new_user = Users.create({
|
||||
'name': name,
|
||||
'login': email,
|
||||
'password': password,
|
||||
'encoach_type': body.get('type', 'student'),
|
||||
'is_verified': body.get('isVerified', True),
|
||||
})
|
||||
|
||||
result = self._serialize(new_user)
|
||||
result['tempPassword'] = password
|
||||
return self._json_response(result, status=201)
|
||||
except Exception:
|
||||
_logger.exception("Make user error")
|
||||
return self._error_response('Internal server error', 500)
|
||||
Reference in New Issue
Block a user