You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

585 lines
21 KiB

# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
import json
import os
import re
from odoo import http
from odoo.http import request
def minify_css(path):
"""
Minify CSS file located at the specified path.
Parameters:
path (str): The file path to the CSS file to be minified.
Returns:
None
This function reads the CSS file specified by the given path, removes
comments,excess whitespace, and redundant CSS properties. It then writes
the minified CSS back to the same file, overwriting its previous contents.
Note:
This function modifies the CSS file in place.
Example:
minify_css('/path/to/style.css')
"""
with open(path, 'r') as f:
css = f.read()
css = re.sub(r'/\*[\s\S]*?\*/', "", css)
css = re.sub(r'url\((["\'])([^)]*)\1\)', r'url(\2)', css)
css = re.sub(r'\s+', ' ', css)
css = re.sub(r'#([0-9a-f])\1([0-9a-f])\2([0-9a-f])\3(\s|;)', r'#\1\2\3\4',
css)
css = re.sub(r':\s*0(\.\d+([cm]m|e[mx]|in|p[ctx]))\s*;', r':\1;', css)
rules = re.findall(r'([^{]+){([^}]*)}', css)
selectors_list = []
css_values = {}
for rule in rules:
selector = rule[0]
content = rule[1]
if selector not in selectors_list:
selectors_list.append(selector)
css_values[selector] = content
else:
css_values[selector] = css_values[selector] + content
with open(path, 'w') as f:
selector_dict = {}
for selector in selectors_list:
rule = css_values[selector].split(';')
dict_rule = {}
for r in rule:
if r:
split_rule = r.split(':')
if len(split_rule) == 2:
dict_rule[split_rule[0].strip()] = split_rule[1]
selector_dict[selector] = dict_rule
f.write('/* This Styles are generated automatically by Theme Studio'
' */\n')
for selector in selector_dict:
f.write(selector + '{')
for rule_data in selector_dict[selector]:
if rule_data != 'pointer-events':
if selector_dict[selector][rule_data].find(
'!important') == -1:
f.write(rule_data + ':' +
selector_dict[selector][rule_data] +
' !important;')
else:
f.write(rule_data + ':' +
selector_dict[selector][rule_data] + ';')
f.write('}')
class ThemeStudio(http.Controller):
"""
Controller class for managing themes in a web application.
This controller handles requests related to managing themes, such as
applying themes, customizing themes, and saving theme settings.
"""
@http.route(['/theme_studio/save_styles'], type="json")
def save_styles(self, kwargs):
"""
Save dynamic styles to a CSS file.
Parameters:
kwargs (dict): A dictionary containing the changed_styles and
object_class.
Returns:
bool: True if the styles are successfully saved, otherwise False.
This function takes the changed_styles and object_class from the
kwargs dictionary and saves them to a CSS file. It appends the styles
to an existing file or creates a new file if it doesn't exist.
After saving the styles, it minifies the CSS file.
Example:
To save styles for a specific object class:
```python
from my_theme_module import save_styles
save_styles({
'changed_styles': {
'color': 'red',
'font-size': '16px'
},
'object_class': 'my-object'
})
```
"""
changed_styles_str = kwargs.get('changed_styles', '{}')
object_class = kwargs.get('object_class', '')
changed_styles = json.loads(changed_styles_str)
working_dir = os.path.dirname(os.path.realpath(__file__))
working_dir = working_dir.replace('/controllers', '')
file_path = working_dir + '/static/src/css/dynamic_styles.css'
style_file = open(file_path, 'a')
if os.stat(file_path).st_size == 0:
style_file.write('/* This file is generated automatically by '
'Theme Infinito */\n')
style_file.write('\n.' + object_class + ' {\n')
for style in changed_styles:
style_file.write(
'\t' + style + ': ' + changed_styles[style] + ';\n')
style_file.write('}\n')
style_file.close()
minify_css(file_path)
return True
@http.route(['/theme_studio/get_current_style'], type="json")
def get_current_style(self, kwargs):
"""
Retrieve the current styles for a given CSS selector.
Parameters:
kwargs (dict): A dictionary containing the 'selector' key
specifying the CSS selector.
Returns:
list or bool: A list of style properties and values for the
specified selector, or False if the selector is not found.
This function reads the CSS file containing dynamic styles and
searches for the specified CSS selector. If the selector is found,
it returns a list of style properties and values associated with that
selector. Each style property-value pair is represented as a list
containing the property and its corresponding value.
If the selector is not found,it returns False.
Example:
To retrieve the current styles for a specific CSS selector:
```python
from my_theme_module import get_current_style
current_styles = get_current_style({
'selector': '.my-selector'
})
print(current_styles)
# Output: [['color', 'red'], ['font-size', '16px']]
```
"""
selector = kwargs.get('selector', '')
working_dir = os.path.dirname(os.path.realpath(__file__))
file_path = working_dir.replace('controllers',
'static/src/css/dynamic_styles.css')
style_file = open(file_path, 'r')
css = style_file.read()
css = re.sub(r'/\*[\s\S]*?\*/', "", css)
css = re.sub(r'url\((["\'])([^)]*)\1\)', r'url(\2)', css)
css = re.sub(r'\s+', ' ', css)
css = re.sub(r'#([0-9a-f])\1([\da-f])\2([0-9a-f])\3(\s|;)',
r'#\1\2\3\4', css)
css = re.sub(r':\s*0(\.\d+([cm]m|e[mx]|in|p[ctx]))\s*;', r':\1;', css)
rules = re.findall(r'([^{]+){([^}]*)}', css)
for rule in rules:
selector_now = rule[0]
content = rule[1]
if selector == selector_now.strip():
contents = content.split(';')
content = []
for c in contents:
c = c.split(':')
if c[0] != '' and len(c) > 1:
content.append(
[c[0], c[1].strip().replace('!important', '')])
return content
return False
@http.route(['/theme_studio/reset_to_default'], type="json")
def reset_to_default(self):
"""
Reset dynamic styles to default.
Returns:
bool: True if the styles are successfully reset, otherwise False.
This function clears the content of the CSS file containing
dynamic styles, effectively resetting all styles to their default
values.
Example:
To reset dynamic styles to default:
```python
from my_theme_module import reset_to_default
reset_to_default()
```
"""
working_dir = os.path.dirname(os.path.realpath(__file__))
file_path = working_dir.replace('controllers',
'static/src/css/dynamic_styles.css')
style_file = open(file_path, 'w')
style_file.write('')
return True
@http.route(['/theme_studio/set_advanced_data'], type="json")
def set_advanced_data(self, args):
"""
Set advanced theme configuration data.
Parameters:
args (list): A list containing a dictionary with the advanced
theme configuration values.
Returns:
bool: True if the configuration data is successfully set,
otherwise False.
This function sets advanced theme configuration data based on the
provided dictionary of values. It updates the configuration
parameters in the database accordingly.
Example:
To set advanced theme configuration data:
```python
from my_theme_module import set_advanced_data
data = [{
'vals': {
'sidebar': True,
'fullscreen': False,
'sidebarIcon': True,
'sidebarName': True,
'sidebarCompany': False,
'sidebarUser': True,
'recentApps': False,
'fullScreenApp': True,
'infinitoRtl': False,
'infinitoDark': True,
'infinitoDarkMode': 'dark',
'infinitoBookmark': True
}
}]
set_advanced_data(data)
```
"""
if args and 'vals' in args[0]:
vals = args[0]['vals']
set_param = request.env['ir.config_parameter'].sudo().set_param
set_param('backend_theme_infinito.is_sidebar_enabled',
vals['sidebar'])
set_param('backend_theme_infinito.is_fullscreen_enabled',
vals['fullscreen'])
set_param('backend_theme_infinito.is_sidebar_icon',
vals['sidebarIcon'])
set_param('backend_theme_infinito.is_sidebar_name',
vals['sidebarName'])
set_param('backend_theme_infinito.is_sidebar_company',
vals['sidebarCompany'])
set_param('backend_theme_infinito.is_sidebar_user',
vals['sidebarUser'])
set_param('backend_theme_infinito.is_recent_apps',
vals['recentApps'])
set_param('backend_theme_infinito.is_fullscreen_app',
vals['fullScreenApp'])
set_param('backend_theme_infinito.is_rtl', vals['infinitoRtl'])
set_param('backend_theme_infinito.is_dark', vals['infinitoDark'])
set_param('backend_theme_infinito.dark_mode',
vals['infinitoDarkMode'])
set_param('backend_theme_infinito.is_menu_bookmark',
vals['infinitoBookmark'])
@http.route(['/theme_studio/set_advanced_data_user'], type="json")
def set_advanced_data_user(self, args):
"""
Set advanced theme configuration data for the current user.
Parameters:
args (list): A list containing a dictionary with the advanced
theme configuration values.
Returns:
bool: True if the configuration data is successfully set for the
user, otherwise False.
This function sets advanced theme configuration data for the current
user based on the provided dictionary of values. It updates the
corresponding fields in the user record accordingly.
Example:
To set advanced theme configuration data for the current user:
```python
from my_theme_module import set_advanced_data_user
data = [{
'vals': {
'sidebar': True,
'fullscreen': False,
'sidebarIcon': True,
'sidebarName': True,
'sidebarCompany': False,
'sidebarUser': True,
'recentApps': False,
'fullScreenApp': True,
'infinitoRtl': False,
'infinitoDark': True,
'infinitoDarkMode': 'dark',
'infinitoBookmark': True,
'loaderClass': 'custom-loader'
}
}]
set_advanced_data_user(data)
```
"""
if args and 'vals' in args[0]:
vals = args[0]['vals']
request.env.user.write({
'is_sidebar_enabled': vals['sidebar'],
'is_fullscreen_enabled': vals['fullscreen'],
'is_sidebar_icon': vals['sidebarIcon'],
'is_sidebar_name': vals['sidebarName'],
'is_sidebar_company': vals['sidebarCompany'],
'is_sidebar_user': vals['sidebarUser'],
'is_recent_apps': vals['recentApps'],
'is_fullscreen_app': vals['fullScreenApp'],
'is_rtl': vals['infinitoRtl'],
'is_dark': vals['infinitoDark'],
'dark_mode': vals['infinitoDarkMode'],
'is_menu_bookmark': vals['infinitoBookmark'],
'loader_class': vals['loaderClass']
})
return True
@http.route(['/theme_studio/add_recent_app'], type="json")
def add_recent_app(self, args):
"""
Add a recent application to the user's recent apps list.
Parameters:
args (list): A list containing a dictionary with the 'appId' key
specifying the ID of the application.
Returns:
bool: True if the recent app is successfully added, otherwise False.
This function adds a recent application to the user's recent apps list
based on the provided application ID. It checks if the provided
arguments are valid and if the user has already reached the maximum
limit of recent apps (5), it removes the oldest one before adding the
new one.
Example:
To add a recent application with ID 123 to the user's recent apps
list:
```python
from my_theme_module import add_recent_app
add_recent_app([{'appId': 123}])
```
"""
if args and isinstance(args, list) and len(args) > 0:
app_id = args[0].get('appId')
if app_id is not None: # Check if appId exists
app_id = int(app_id)
else:
# Handle the case where appId is not provided
# You might want to raise an error, log a message, or handle
# it differently based on your requirements
# For now, I'll assign a default value of 0
app_id = 0
else:
# Handle the case where args is empty or not a list
# You might want to raise an error or handle it differently based
# on your requirements For now, I'll assign a default value of 0
app_id = 0
recent_app = request.env['recent.apps'].sudo()
exist = recent_app.search([
('app_id', '=', app_id),
('user_id', '=', request.env.user.id)
])
exist.unlink() if exist else None
total_recent = recent_app.search(
[('user_id', '=', request.env.user.id)])
if len(total_recent) > 4:
total_recent[0].unlink()
recent_app.create({
'app_id': app_id,
'user_id': request.env.user.id
})
@http.route(['/theme_studio/get_recent_apps'], type="json")
def get_recent_apps(self):
"""
Retrieve the list of recent applications for the current user.
Returns:
list: A list of dictionaries containing the recent applications'
information,
or an empty list if no recent apps are found.
This function retrieves the list of recent applications for the current
user from the database. It returns a list of dictionaries containing the
information of each recent application, such as its ID, name, and other
relevant details.
Example:
To retrieve the list of recent applications for the current user:
```python
from my_theme_module import get_recent_apps
recent_apps = get_recent_apps()
print(recent_apps)
```
"""
recent_app = request.env['recent.apps'].sudo()
return recent_app.search_read([
('user_id', '=', request.env.user.id)
])
@http.route(['/theme_studio/add_menu_bookmarks'], type="json")
def add_menu_bookmarks(self, args):
"""
Add a menu bookmark for the current user.
Parameters:
args (dict): A dictionary containing the menu data including
'actionId' and 'menuUrl'.
Returns:
bool: True if the menu bookmark is successfully added, otherwise
False.
This function adds a menu bookmark for the current user based on the
provided
menu data. It extracts the action ID and URL from the menu data and
creates a
new menu bookmark record in the database.
Example:
To add a menu bookmark with action ID 123 and URL '/dashboard' for
the current user:
```python
from my_theme_module import add_menu_bookmarks
menu_data = {
'actionId': 123,
'menuUrl': '/dashboard'
}
add_menu_bookmarks({'menu': menu_data})
```
"""
menu_data = args.get('menu', {})
action_id = menu_data.get('actionId')
user_id = request.env.user.id
url = menu_data.get('menuUrl')
menu_bookmark = request.env['infinito.menu.bookmark'].sudo()
menu_bookmark.create({
'action_id': int((action_id)),
'user_id': user_id,
'url': url,
})
@http.route(['/theme_studio/remove_menu_bookmarks'], type="json")
def remove_menu_bookmarks(self, args):
"""
Remove a menu bookmark for the current user.
Parameters:
args (dict): A dictionary containing the menu data including
'actionId'.
Returns:
bool: True if the menu bookmark is successfully removed,
otherwise False.
This function removes a menu bookmark for the current user based on
the provided
action ID. It searches for the menu bookmark record in the database and
deletes
it if found.
Example:
To remove a menu bookmark with action ID 123 for the current user:
```python
from my_theme_module import remove_menu_bookmarks
menu_data = {
'actionId': 123
}
remove_menu_bookmarks({'menu': menu_data})
```
"""
menu_data = args.get('menu', {})
action_id = menu_data.get('actionId')
user_id = request.env.user.id
menu_bookmark = request.env['infinito.menu.bookmark'].sudo().search([
('action_id', '=', int(action_id)),
('user_id', '=', user_id)
])
if menu_bookmark:
menu_bookmark.unlink()
@http.route(['/theme_studio/get_presets'], type="json")
def get_presets(self):
"""
Retrieve the list of available presets.
Returns:
list: A list of dictionaries containing the available presets.
This function reads the presets data from a JSON file and returns
it as a list of dictionaries.
Each dictionary in the list represents a preset with
its configuration details.
Example:
To retrieve the list of available presets:
```python
from my_theme_module import get_presets
presets = get_presets()
print(presets)
```
"""
working_dir = os.path.dirname(os.path.realpath(__file__))
working_dir = working_dir.replace('/controllers', '')
file_path = working_dir + '/static/src/json/presets.json'
file = open(file_path, 'r')
presets = json.load(file)
return presets