bemade-addons/odoo_to_odoo_bemade/models/api_key.py
mathis 4d92c5a72f [IMP] odoo_to_odoo_sync: implement dependency management, fix connection errors, and add field mapping
- Added comprehensive dependency management with proper OdooRPC library integration
- Fixed XML-RPC, JSON-RPC, and OdooRPC connection authentication issues
- Implemented proper Odoo 18 API key format support with scope parameter
- Added intelligent field mapping wizard with Full/Required/Balanced modes
- Enhanced error handling and connection state management
- Removed legacy API key system for clean reinstall capability
- Added detailed debug logging for connection troubleshooting
2025-08-15 08:40:48 -04:00

211 lines
5.4 KiB
Python

# -*- coding: utf-8 -*-
# Copyright 2025 Bemade
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.html)
"""API Key Management for Bemade Odoo Sync.
This module provides functionality for generating, tracking, and revoking
API keys used for authentication between Odoo instances.
"""
import logging
import secrets
import string
from datetime import datetime
from odoo import api, fields, models, _
from odoo.exceptions import UserError
_logger = logging.getLogger(__name__)
class OdooToBemadeApiKey(models.Model):
"""API Key for Bemade Odoo Sync.
This model stores API keys that can be used for authentication
between Odoo instances.
"""
_name = 'odoo.to.bemade.api.key'
_description = 'Bemade API Key'
_order = 'create_date desc'
name = fields.Char(
string='Name',
required=True,
help='A descriptive name for this API key',
)
key = fields.Char(
string='API Key',
readonly=True,
copy=False,
help='The API key value (only shown once upon creation)',
)
key_hash = fields.Char(
string='API Key Hash',
readonly=True,
copy=False,
help='Hashed value of the API key for verification',
)
user_id = fields.Many2one(
'res.users',
string='Created By',
default=lambda self: self.env.user,
readonly=True,
required=True,
help='User who created this API key',
)
create_date = fields.Datetime(
string='Created On',
readonly=True,
)
last_used = fields.Datetime(
string='Last Used',
readonly=True,
help='Last time this API key was used for authentication',
)
expiration_date = fields.Date(
string='Expiration Date',
help='Date when this API key expires (leave empty for no expiration)',
)
is_active = fields.Boolean(
string='Active',
default=True,
help='Whether this API key is active and can be used for authentication',
)
instance_ids = fields.One2many(
'odoo.to.bemade.instance',
'api_key_id',
string='Used In Instances',
help='Instances using this API key',
)
usage_count = fields.Integer(
string='Usage Count',
default=0,
readonly=True,
help='Number of times this API key has been used',
)
notes = fields.Text(
string='Notes',
help='Additional notes about this API key',
)
@api.model
def generate_key(self):
"""Generate a new API key.
Returns:
str: The generated API key
"""
# Generate a random 32-character string
alphabet = string.ascii_letters + string.digits
key = ''.join(secrets.choice(alphabet) for _ in range(32))
return key
def action_generate_key(self):
"""Generate a new API key and store its hash.
Returns:
dict: Action to open a wizard showing the generated key
"""
self.ensure_one()
# Generate a new API key
key = self.generate_key()
# Store the key hash (in a real implementation, use a proper hashing algorithm)
# For this example, we're just storing the key directly, but in production
# you should use a secure hashing algorithm like bcrypt
self.write({
'key': key,
'key_hash': key, # In production, store a hash instead
'is_active': True,
})
# Return an action to open a wizard showing the key
return {
'name': _('API Key Generated'),
'type': 'ir.actions.act_window',
'res_model': 'odoo.to.bemade.api.key.display',
'view_mode': 'form',
'target': 'new',
'context': {
'default_api_key_id': self.id,
'default_api_key': key,
},
}
def action_revoke(self):
"""Revoke this API key.
Returns:
bool: True
"""
self.ensure_one()
self.write({
'is_active': False,
})
return True
def action_activate(self):
"""Activate this API key.
Returns:
bool: True
"""
self.ensure_one()
self.write({
'is_active': True,
})
return True
def record_usage(self):
"""Record that this API key has been used.
Returns:
bool: True
"""
self.ensure_one()
self.write({
'last_used': fields.Datetime.now(),
'usage_count': self.usage_count + 1,
})
return True
@api.model
def validate_key(self, key):
"""Validate an API key.
Args:
key (str): The API key to validate
Returns:
bool: True if the key is valid, False otherwise
"""
# In a real implementation, hash the key and compare with stored hashes
# For this example, we're just comparing the key directly
api_key = self.search([
('key_hash', '=', key),
('is_active', '=', True),
], limit=1)
if not api_key:
return False
# Check if the key has expired
if api_key.expiration_date and api_key.expiration_date < fields.Date.today():
return False
# Record usage
api_key.record_usage()
return True