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
150 lines
5.9 KiB
Python
150 lines
5.9 KiB
Python
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)
|