Includes: - Odoo 19 framework (odoo/) - 27 custom EnCoach addons (new_project/custom_addons/) - encoach_core, encoach_api, encoach_lms_api, encoach_adaptive_api - encoach_exam, encoach_taxonomy, encoach_adaptive, encoach_assignment - encoach_ai, encoach_ai_grading, encoach_ai_generation, encoach_ai_media - encoach_courseware, encoach_communication, encoach_subscription - encoach_notification, encoach_approval, encoach_branding - encoach_classroom, encoach_registration, encoach_stats - encoach_faq, encoach_ticket, encoach_training, encoach_resources - encoach_adaptive_ai, encoach_sis - 21 OpenEduCat Enterprise modules (new_project/enterprise-19/) - 14 OpenEduCat Community modules (new_project/openeducat_erp-19.0/) - Configuration: odoo.conf, requirements.txt, scripts - 200+ REST API endpoints with JWT authentication - SRS and test documentation Made-with: Cursor
107 lines
4.5 KiB
Python
107 lines
4.5 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import fields, models
|
|
from odoo.fields import Domain
|
|
|
|
|
|
class IrAsset(models.Model):
|
|
_inherit = 'ir.asset'
|
|
|
|
key = fields.Char(copy=False) # used to resolve multiple assets in a multi-website environment
|
|
website_id = fields.Many2one('website', ondelete='cascade')
|
|
|
|
def _get_asset_params(self):
|
|
params = super()._get_asset_params()
|
|
params['website_id'] = self.env['website'].get_current_website(fallback=False).id
|
|
return params
|
|
|
|
def _get_asset_bundle_url(self, filename, unique, assets_params, ignore_params=False):
|
|
route_prefix = '/web/assets'
|
|
if ignore_params: # we dont care about website id, match both
|
|
route_prefix = '/web/assets%'
|
|
elif website_id := assets_params.get('website_id', None):
|
|
route_prefix = f'/web/assets/{website_id}'
|
|
return f'{route_prefix}/{unique}/{filename}'
|
|
|
|
def _get_related_assets(self, domain, *, website_id=None, **params):
|
|
if website_id:
|
|
domain = Domain(domain) & self.env['website'].browse(website_id).website_domain()
|
|
assets = super()._get_related_assets(domain, **params)
|
|
return assets.filter_duplicate(website_id)
|
|
|
|
def _get_active_addons_list(self, *, website_id=None, **params):
|
|
"""Overridden to discard inactive themes."""
|
|
addons_list = super()._get_active_addons_list(**params)
|
|
|
|
if not website_id:
|
|
return addons_list
|
|
|
|
IrModule = self.env['ir.module.module'].sudo()
|
|
# discard all theme modules except website.theme_id
|
|
themes = IrModule.search(IrModule.get_themes_domain()) - self.env["website"].browse(website_id).theme_id
|
|
to_remove = set(themes.mapped('name'))
|
|
|
|
return [name for name in addons_list if name not in to_remove]
|
|
|
|
def filter_duplicate(self, website_id=None):
|
|
""" Filter current recordset only keeping the most suitable asset per distinct name.
|
|
Every non-accessible asset will be removed from the set:
|
|
|
|
* In non website context, every asset with a website will be removed
|
|
* In a website context, every asset from another website
|
|
"""
|
|
if website_id is None:
|
|
website_id = self.env['website'].get_current_website(fallback=False).id
|
|
if not website_id:
|
|
return self.filtered(lambda asset: not asset.website_id)
|
|
|
|
specific_asset_keys = {asset.key for asset in self if asset.website_id.id == website_id and asset.key}
|
|
most_specific_assets = []
|
|
for asset in self:
|
|
if asset.website_id:
|
|
# specific asset: add it if it's for the current website and ignore
|
|
# it if it's for another website
|
|
if asset.website_id.id == website_id:
|
|
most_specific_assets.append(asset)
|
|
continue
|
|
elif not asset.key:
|
|
# no key: added either way
|
|
most_specific_assets.append(asset)
|
|
elif asset.key not in specific_asset_keys:
|
|
# generic asset: add it iff for the current website, there is no
|
|
# specific asset for this asset (based on the same `key` attribute)
|
|
most_specific_assets.append(asset)
|
|
|
|
return self.browse().union(*most_specific_assets)
|
|
|
|
def write(self, vals):
|
|
"""COW for ir.asset. This way editing websites does not impact other
|
|
websites. Also this way newly created websites will only
|
|
contain the default assets.
|
|
"""
|
|
current_website_id = self.env.context.get('website_id')
|
|
if not current_website_id or self.env.context.get('no_cow'):
|
|
return super().write(vals)
|
|
|
|
for asset in self.with_context(active_test=False):
|
|
# No need of COW if the asset is already specific
|
|
if asset.website_id:
|
|
super(IrAsset, asset).write(vals)
|
|
continue
|
|
|
|
# If already a specific asset for this generic asset, write on it
|
|
website_specific_asset = asset.search([
|
|
('key', '=', asset.key),
|
|
('website_id', '=', current_website_id)
|
|
], limit=1)
|
|
if website_specific_asset:
|
|
super(IrAsset, website_specific_asset).write(vals)
|
|
continue
|
|
|
|
copy_vals = {'website_id': current_website_id, 'key': asset.key}
|
|
website_specific_asset = asset.copy(copy_vals)
|
|
|
|
super(IrAsset, website_specific_asset).write(vals)
|
|
|
|
return True
|