diff --git a/odoo_unifi_manager.zip b/odoo_unifi_manager.zip new file mode 100644 index 0000000..2b46e9b Binary files /dev/null and b/odoo_unifi_manager.zip differ diff --git a/odoo_unifi_manager/__manifest__.py b/odoo_unifi_manager/__manifest__.py index 694c23a..edfbbe6 100644 --- a/odoo_unifi_manager/__manifest__.py +++ b/odoo_unifi_manager/__manifest__.py @@ -8,10 +8,13 @@ 'base' ], 'data': [ - 'views/firewall_rule_wizard_action.xml', + 'views/controller_views.xml', + 'views/firewall_rule_action.xml', 'views/firewall_rule_views.xml', 'views/firewall_rule_template_views.xml', - # 'views/unify_menu.xml', + 'views/network_views.xml', + 'views/wifi_views.xml', + 'views/unify_menu.xml', 'security/ir.model.access.csv' ], 'installable': True, diff --git a/odoo_unifi_manager/models/__init__.py b/odoo_unifi_manager/models/__init__.py index 71d8e69..459bf4a 100644 --- a/odoo_unifi_manager/models/__init__.py +++ b/odoo_unifi_manager/models/__init__.py @@ -1,2 +1,6 @@ +from . import ctrl from . import firewall_rule from . import firewall_rule_template +from . import network +from . import wifi +from . import unifi_client diff --git a/odoo_unifi_manager/models/ctrl.py b/odoo_unifi_manager/models/ctrl.py new file mode 100644 index 0000000..b9a8d1d --- /dev/null +++ b/odoo_unifi_manager/models/ctrl.py @@ -0,0 +1,57 @@ +from .unifi_client import Unifi + +from odoo import models, fields, api +from odoo.exceptions import ValidationError +#from unificontrol import UnifiClient + + +class UnifiCtrl(models.Model): + _name = 'unifi.ctrl' + _description = 'Unifi Controller' + + name = fields.Char( + string='Name', + required=True + ) + + ip_address = fields.Char( + string='IP Address', + required=True, + help="IP address of the Unifi Controller." + ) + + api_port = fields.Integer( + string='API Port', + default=8443, + help="Port used for the Unifi API." + ) + + username = fields.Char( + string='Username', + required=True, + help="Username for API authentication." + ) + + password = fields.Char( + string='Password', + required=True, + help="Password for API authentication." + ) + + def action_test_connection(self): + """Test connection to Unifi Controller.""" + self.ensure_one() + client = Unifi(self.ip_address, self.username, self.password) + try: + client.login() + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'title': 'Success', + 'message': 'Connection successful!', + 'type': 'success', + }, + } + except Exception as e: + raise ValidationError(f"Connection failed: {e}") \ No newline at end of file diff --git a/odoo_unifi_manager/models/firewall_rule.py b/odoo_unifi_manager/models/firewall_rule.py index 99a764b..6ea8984 100644 --- a/odoo_unifi_manager/models/firewall_rule.py +++ b/odoo_unifi_manager/models/firewall_rule.py @@ -9,6 +9,13 @@ class FirewallRule(models.Model): required=True ) + ctrl_id = fields.Many2one( + 'unifi.ctrl', + string='Controller', + required=True, + help="Controller where this rule is applied." + ) + action = fields.Selection( selection=[ ('accept', 'Accept'), diff --git a/odoo_unifi_manager/models/firewall_rule_template.py b/odoo_unifi_manager/models/firewall_rule_template.py index fa5baa0..7b008ba 100644 --- a/odoo_unifi_manager/models/firewall_rule_template.py +++ b/odoo_unifi_manager/models/firewall_rule_template.py @@ -8,7 +8,14 @@ class FirewallRuleTemplate(models.Model): string='Template Name', required=True ) - + + ctrl_id = fields.Many2one( + 'unifi.ctrl', + string='Controller', + required=True, + help="Controller where this rule is applied." + ) + action = fields.Selection( selection=[ ('accept', 'Accept'), diff --git a/odoo_unifi_manager/models/network.py b/odoo_unifi_manager/models/network.py new file mode 100644 index 0000000..5f3e943 --- /dev/null +++ b/odoo_unifi_manager/models/network.py @@ -0,0 +1,37 @@ +from odoo import models, fields + +class Network(models.Model): + _name = 'unifi.network' + _description = 'Unifi Network' + + name = fields.Char( + string='Network Name', + required=True + ) + + cidr = fields.Char( + string='CIDR', + required=True, + help="CIDR notation for the network (e.g., 192.168.1.0/24)." + ) + + gateway = fields.Char( + string='Gateway', + help="Gateway IP address for the network." + ) + + vlan_id = fields.Integer( + string='VLAN ID', + help="VLAN ID for the network." + ) + + description = fields.Text( + string='Description' + ) + + ctrl_id = fields.Many2one( + 'unifi.ctrl', + string='Controller', + required=True, + help="Controller where this rule is applied." + ) diff --git a/odoo_unifi_manager/models/unifi_client.py b/odoo_unifi_manager/models/unifi_client.py new file mode 100644 index 0000000..0c7d816 --- /dev/null +++ b/odoo_unifi_manager/models/unifi_client.py @@ -0,0 +1,73 @@ +import requests +import urllib3 +from odoo.exceptions import ValidationError + +UNIFI_LOGIN_PATH = '/api/auth/login' +UNIFI_SITES_PATH = '/api/self/sites' + +# Désactiver les avertissements SSL pour certificats auto-signés +urllib3.disable_warnings() + + +class Unifi: + def __init__(self, host, username, password): + """Initialize Unifi client.""" + self.host = host + self.username = username + self.password = password + self.session = requests.Session() + self.csrf = "" + + def login(self): + """Authenticate with the Unifi Controller.""" + payload = { + "username": self.username, + "password": self.password, + } + try: + r = self.request(UNIFI_LOGIN_PATH, payload) + if r.ok: + return True + else: + raise ValidationError(f"Login failed: {r.text}") + except requests.RequestException as e: + raise ValidationError(f"Failed to connect to Unifi Controller: {e}") + + def request(self, path, data=None, method='POST'): + """Send a request to the Unifi API.""" + if data is None: + data = {} + uri = f'https://{self.host}{path}' + headers = { + "Accept": "application/json", + "Content-Type": "application/json; charset=utf-8", + } + if self.csrf: + headers["X-CSRF-Token"] = self.csrf + try: + r = getattr(self.session, method.lower())(uri, json=data, verify=False, headers=headers) + if 'X-CSRF-Token' in r.headers: + self.csrf = r.headers['X-CSRF-Token'] + return r + except requests.RequestException as e: + raise ValidationError(f"Request to Unifi Controller failed: {e}") + + def get_sites(self): + """Retrieve available sites.""" + try: + r = self.request(UNIFI_SITES_PATH, method='GET') + if r.ok: + return r.json().get('data', []) + else: + raise ValidationError(f"Failed to retrieve sites: {r.text}") + except requests.RequestException as e: + raise ValidationError(f"Failed to retrieve sites: {e}") + + def test_connection(self): + """Test connection and fetch available sites.""" + if not self.login(): + raise ValidationError("Login failed. Check your credentials.") + + sites = self.get_sites() + site_list = [site['desc'] for site in sites] + return f"Connection successful! Available sites: {', '.join(site_list)}" \ No newline at end of file diff --git a/odoo_unifi_manager/models/wifi.py b/odoo_unifi_manager/models/wifi.py new file mode 100644 index 0000000..f286180 --- /dev/null +++ b/odoo_unifi_manager/models/wifi.py @@ -0,0 +1,35 @@ +from odoo import models, fields + +class Wifi(models.Model): + _name = 'unifi.wifi' + _description = 'Unifi WiFi Network' + + name = fields.Char(string='WiFi Name (SSID)', required=True) + security_mode = fields.Selection( + [('open', 'Open'), ('wpa', 'WPA/WPA2 Personal'), ('wpa3', 'WPA3')], + string='Security Mode', + required=True, + default='wpa' + ) + + password = fields.Char( + string='WiFi Password', + help="Password for the WiFi network (if applicable)." + ) + + vlan_id = fields.Many2one( + comodel_name='unifi.network', + string='VLAN', + help="VLAN associated with this WiFi network." + ) + + description = fields.Text( + string='Description' + ) + + ctrl_id = fields.Many2one( + 'unifi.ctrl', + string='Controller', + required=True, + help="Controller where this rule is applied." + ) diff --git a/odoo_unifi_manager/security/ir.model.access.csv b/odoo_unifi_manager/security/ir.model.access.csv index d449dfc..6dc6eb8 100644 --- a/odoo_unifi_manager/security/ir.model.access.csv +++ b/odoo_unifi_manager/security/ir.model.access.csv @@ -2,3 +2,6 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink odoo_unifi_manager.access_unifi_firewall_rule,access_unifi_firewall_rule,odoo_unifi_manager.model_unifi_firewall_rule,base.group_user,1,0,0,0 odoo_unifi_manager.access_unifi_firewall_rule_template,access_unifi_firewall_rule_template,odoo_unifi_manager.model_unifi_firewall_rule_template,base.group_user,1,0,0,0 odoo_unifi_manager.access_unifi_firewall_rule_wizard,access_unifi_firewall_rule_wizard,odoo_unifi_manager.model_unifi_firewall_rule_wizard,base.group_user,1,0,0,0 +odoo_unifi_manager.access_unifi_network,access_unifi_network,odoo_unifi_manager.model_unifi_network,base.group_user,1,1,1,0 +odoo_unifi_manager.access_unifi_wifi,access_unifi_wifi,odoo_unifi_manager.model_unifi_wifi,base.group_user,1,1,1,0 +odoo_unifi_manager.access_unifi_ctrl,access_unifi_ctrl,odoo_unifi_manager.model_unifi_ctrl,base.group_system,1,1,1,1 \ No newline at end of file diff --git a/odoo_unifi_manager/static/description/icon.png b/odoo_unifi_manager/static/description/icon.png new file mode 100644 index 0000000..8f5438e Binary files /dev/null and b/odoo_unifi_manager/static/description/icon.png differ diff --git a/odoo_unifi_manager/views/controller_views.xml b/odoo_unifi_manager/views/controller_views.xml new file mode 100644 index 0000000..1ee6722 --- /dev/null +++ b/odoo_unifi_manager/views/controller_views.xml @@ -0,0 +1,46 @@ + + + + Controllers + unifi.ctrl + tree,form + +

+ Manage your Unifi Controllers here. +

+
+
+ + + + unifi.ctrl.tree + unifi.ctrl + + + + + + + + + + + + unifi.ctrl.form + unifi.ctrl + +
+ + + + + + + +