Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • coopdevs/comunitats-energetiques/odoo-ce
1 result
Show changes
Commits on Source (9)
......@@ -71,6 +71,7 @@
'data/mail_template_data.xml',
'data/mail_template_update_data.xml',
'wizards/multicompany_easy_creation.xml',
'wizards/assign_admin_wizard.xml',
],
'installable': True,
'application': True,
......
......@@ -8,6 +8,7 @@ URL_AUTH = "{root_endpoint}realms/{realm_name}/protocol/openid-connect/auth"
URL_VALIDATION = "{root_endpoint}realms/{realm_name}/protocol/openid-connect/userinfo"
URL_TOKEN = "{root_endpoint}realms/{realm_name}/protocol/openid-connect/token"
URL_JWKS = "{root_endpoint}realms/{realm_name}/protocol/openid-connect/certs"
URL_RESET_PASSWORD = "{root_endpoint}admin/realms/{realm_name}/users/{kc_uid}/execute-actions-email?redirect_uri={odoo_url}&client_id={cliend_id}"
class OAuthProvider(models.Model):
......@@ -22,6 +23,8 @@ class OAuthProvider(models.Model):
admin_user_endpoint = fields.Char(string='User admin URL', required=True)
root_endpoint = fields.Char(string='Root URL', required=True, default='http://keycloak-ccee.local:8080/auth/')
realm_name = fields.Char(string='Realm name', required=True, default='0')
reset_password_endpoint = fields.Char(string='Reset password URL')
redirect_admin_url = fields.Char(string='Redirect Link after update password')
def validate_admin_provider(self):
if not self.client_secret:
......@@ -31,6 +34,7 @@ class OAuthProvider(models.Model):
@api.onchange('root_endpoint')
def _onchange_root_endpoint(self):
# TODO: Duplicated code? 🤔
if self.is_keycloak_provider and self.root_endpoint and self.realm_name:
self.admin_user_endpoint = URL_ADMIN_USERS.format(**{'root_endpoint': self.root_endpoint,
'realm_name': self.realm_name})
......@@ -42,9 +46,17 @@ class OAuthProvider(models.Model):
'realm_name': self.realm_name})
self.jwks_uri = URL_JWKS.format(**{'root_endpoint': self.root_endpoint,
'realm_name': self.realm_name})
self.reset_password_endpoint = URL_RESET_PASSWORD.format(
root_endpoint=self.root_endpoint,
realm_name=self.realm_name,
kc_uid='{kc_uid}',
odoo_url=self.redirect_admin_url,
cliend_id=self.client_id,
)
@api.onchange('realm_name')
def _onchange_realm_name(self):
# TODO: Duplicated code? 🤔
if self.is_keycloak_provider and self.root_endpoint and self.realm_name:
self.admin_user_endpoint = URL_ADMIN_USERS.format(**{'root_endpoint': self.root_endpoint,
'realm_name': self.realm_name})
......@@ -56,6 +68,13 @@ class OAuthProvider(models.Model):
'realm_name': self.realm_name})
self.jwks_uri = URL_JWKS.format(**{'root_endpoint': self.root_endpoint,
'realm_name': self.realm_name})
self.reset_password_endpoint = URL_RESET_PASSWORD.format(
root_endpoint=self.root_endpoint,
realm_name=self.realm_name,
kc_uid='{kc_uid}',
odoo_url=self.redirect_admin_url,
cliend_id=self.client_id,
)
def get_auth_link(self):
self.ensure_one()
......
......@@ -71,6 +71,13 @@ class ResCompany(models.Model):
)
wordpress_base_url = fields.Char(
string=_("Wordpress Base URL (JWT auth)")
admins = fields.One2many(
'res.users',
string=_("Community admins"),
compute='_get_admins',
readonly=True,
store=False
)
@api.constrains('hierarchy_level', 'parent_id')
......@@ -128,6 +135,55 @@ class ResCompany(models.Model):
admins_user_ids.append(role_line.user_id.id)
return any([user in admins_user_ids for user in company_user_ids])
def _get_admin_role_name(self):
if self.hierarchy_level == 'community':
return "role_ce_admin"
elif self.hierarchy_level == 'coordinator':
return "role_coordination"
elif self.hierarchy_level == 'instance':
return "role_platform_admin"
def _get_admins(self):
role_name = self._get_admin_role_name()
for rec in self:
role_lines = self.env["res.users.role.line"].sudo().search([
("company_id.id", "=", self.id),
("active", "=", True),
("role_id.code", "=", role_name)
])
rec.admins = role_lines.mapped("user_id")
def add_ce_admin(self, user):
role_name = self._get_admin_role_name()
role = self.env["res.users.role"].sudo().search([(
"code", "=", role_name
)])
current_role = self.env["res.users.role.line"].sudo().search([
("user_id", "=", user.id),
("active", "=", True),
("company_id", "=", self.id)
])
if current_role and len(current_role) > 1:
raise UserError(_("Error: This user have multiple roles for this company"))
if current_role and len(current_role.company_ids) > 1:
raise UserError(_("Error: One role line can't have multiple users"))
if current_role and current_role.role.code != "role_ce_member":
raise UserError(_("Error: You can't remove {} role").format(current_role.role.code))
if current_role:
current_role.write({"role_id": role})
else:
user = self.env["res.users"].sudo().browse(user.id)
user.write({
"company_ids": [(4, self.id)]
})
self.env["res.users.role.line"].sudo().create({
"user_id": user.id,
"active": True,
"role_id": role.id,
"company_id": self.id,
})
def get_ce_members(self, domain_key="in_kc_and_active"):
domains_dict = {
"in_kc_and_active": [
......@@ -236,6 +292,15 @@ class ResCompany(models.Model):
self.landing_page_id.write(
{"wp_landing_page_id": landing_page['id']})
def action_open_assign_admin_wizard(self):
return {
'name': 'Example Wizard',
'type': 'ir.actions.act_window',
'res_model': 'assign.admin.wizard',
'view_mode': 'form',
'target': 'new',
}
def get_landing_page_form(self):
return {
"type": "ir.actions.act_window",
......
......@@ -135,7 +135,8 @@ class ResUsers(models.Model):
values = {
'username': odoo_user.login,
'email': odoo_user.partner_id.email,
'attributes': {'lang': [odoo_user.lang]}
'attributes': {'lang': [odoo_user.lang]},
'enabled': True,
}
if 'firstname' in odoo_user.partner_id:
......@@ -181,3 +182,32 @@ class ResUsers(models.Model):
def get_role_codes(self):
#TODO Map all code to company and enable (We should update the API schema too)
return self.role_line_ids[0].role_id.code
def get_administrared_ce(self):
communities = []
role_lines = self.env["res.users.role.line"].sudo().search([
("user_id.id", "=", self.id),
("active", "=", True),
("role_id.code", "=", "role_ce_admin")
])
for role_line in role_lines:
for company in role_line.allowed_company_ids:
communities.append(company.id)
return communities
def send_reset_password_mail(self):
provider_id = self.env.ref('energy_communities.keycloak_admin_provider')
provider_id.validate_admin_provider()
headers = {
'Authorization': 'Bearer %s' % self._get_admin_token(provider_id)
}
headers['Content-Type'] = "application/json"
endpoint = provider_id.reset_password_endpoint.format(
kc_uid = self.oauth_uid
)
response = requests.put(endpoint, headers=headers, data='["UPDATE_PASSWORD", "VERIFY_EMAIL"]')
if response.status_code != 204:
raise exceptions.UserError(
_('Something went wrong. Mail can not be sended. More details: {}').format(response.json())
)
......@@ -16,6 +16,10 @@
('is_keycloak_provider', '=', False)]}"/>
<field name="admin_user_endpoint" attrs="{'invisible': ['|', ('is_admin_provider','=',False),
('is_keycloak_provider', '=', False)]}"/>
<field name="redirect_admin_url" attrs="{'invisible': ['|', ('is_admin_provider','=',False),
('is_keycloak_provider', '=', False)]}"/>
<field name="reset_password_endpoint" attrs="{'invisible': ['|', ('is_admin_provider','=',False),
('is_keycloak_provider', '=', False)]}"/>
</xpath>
</field>
</record>
......
......@@ -11,25 +11,15 @@
<xpath expr="//sheet" position="before">
<header>
<field name="landing_page_id" invisible="1"/>
<button
name="create_landing"
type="object"
string="Create landing page"
attrs="{'invisible': [('landing_page_id','!=',False)]}"
/>
<button name="create_landing" type="object" string="Create landing page" attrs="{'invisible': [('landing_page_id','!=',False)]}" />
<button name="action_open_assign_admin_wizard" type="object" string="Assing administrator" groups="['group_admin','group_platform_manager','group_coordinator']"/>
</header>
</xpath>
<xpath expr="//field[@name='logo']" position="before">
<div class='oe_button_box'>
<button
name="get_landing_page_form"
type="object"
string="My landing page"
class="oe_stat_button"
icon="fa-globe"
attrs="{'invisible': [('landing_page_id','=',False)]}"
/>
<button name="get_landing_page_form" type="object" string="My landing page" class="oe_stat_button" icon="fa-globe" attrs="{'invisible': [('landing_page_id','=',False)]}" />
</div>
<field name="admins" invisible="True"></field>
</xpath>
<xpath expr="//notebook" position="inside">
<page string="Energy Communities">
......@@ -39,6 +29,7 @@
<field name="parent_id" domain="[('id', 'in', parent_id_filtered_ids)]"></field>
<field name="voluntary_share_id"></field>
<field name="ce_tag_ids"/>
<field name="admins"/>
</group>
</page>
</xpath>
......
from . import multicompany_easy_creation
from . import assign_admin_wizard
\ No newline at end of file
from odoo import models, fields, api
from odoo.tools.translate import _
from odoo.exceptions import ValidationError
class AssignAdminWizard(models.TransientModel):
_name = 'assign.admin.wizard'
_description = 'Assign admin Wizard'
is_new_admin = fields.Boolean(
string=_("Is a new admin?")
)
first_name = fields.Char(string=_("First name"))
last_name = fields.Char(string=_("Last name"))
vat = fields.Char(string=_("VAT"))
email = fields.Char(string=_("Email"))
lang = fields.Many2one(
'res.lang',
string=_("Language")
)
def process_data(self):
company_ids = self.env.context.get('active_ids')
if not company_ids:
raise ValidationError(_('Company not found'))
company_id = company_ids[0]
if self.is_new_admin:
user = self.create_user(company_id)
else:
user = self.env['res.users'].search([('login', '=', self.vat)])
company = self.env['res.company'].browse(company_id)
company.add_ce_admin(user)
return True
# TODO: Move this method inside res_users
def create_user(self, company_id):
vals = {
"login": self.vat,
"firstname": self.first_name,
"lastname": self.last_name,
"company_id": company_id,
"company_ids": [company_id],
"lang": self.lang.code,
"email": self.email,
}
user = self.env["res.users"].create(vals)
user.create_users_on_keycloak()
user.send_reset_password_mail()
return user
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_assign_admin_wizard_form" model="ir.ui.view">
<field name="name">assign.admin.wizard.form</field>
<field name="model">assign.admin.wizard</field>
<field name="arch" type="xml">
<form string="Assign Admin Wizard">
<sheet>
<group>
<field name="is_new_admin"/>
</group>
<group>
<field name="vat"/>
<field name="first_name" attrs="{'invisible':[('is_new_admin', '=', False)]}"/>
<field name="last_name" attrs="{'invisible':[('is_new_admin', '=', False)]}"/>
<field name="email" attrs="{'invisible':[('is_new_admin', '=', False)]}"/>
<field name="lang" attrs="{'invisible':[('is_new_admin', '=', False)]}"/>
</group>
</sheet>
<footer>
<button name="process_data" string="Procesar" type="object" class="btn-primary"/>
<button string="Cancelar" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
</data>
</odoo>
\ No newline at end of file