-
1galicea_base/README.md
-
2galicea_base/__init__.py
-
23galicea_base/__manifest__.py
-
6galicea_base/views/base_menu.xml
-
1galicea_environment_checkup/README.md
-
9galicea_environment_checkup/__init__.py
-
32galicea_environment_checkup/__manifest__.py
-
3galicea_environment_checkup/controllers/__init__.py
-
26galicea_environment_checkup/controllers/dashboard.py
-
4galicea_environment_checkup/environment_checkup/__init__.py
-
49galicea_environment_checkup/environment_checkup/core.py
-
30galicea_environment_checkup/environment_checkup/custom.py
-
183galicea_environment_checkup/environment_checkup/dependencies.py
-
24galicea_environment_checkup/environment_checkup/runtime.py
-
0galicea_environment_checkup/environment_checkup/utils.py
-
1galicea_environment_checkup/models/__init__.py
-
19galicea_environment_checkup/models/ext_module.py
-
BINgalicea_environment_checkup/static/description/icon.png
-
BINgalicea_environment_checkup/static/description/images/custom_screenshot.png
-
BINgalicea_environment_checkup/static/description/images/dependencies_screenshot.png
-
79galicea_environment_checkup/static/description/index.html
-
146galicea_environment_checkup/static/src/js/environment_checkup.js
-
108galicea_environment_checkup/static/src/js/environment_checkup10.js
-
71galicea_environment_checkup/static/src/xml/templates.xml
-
9galicea_environment_checkup/views/data.xml
-
17galicea_environment_checkup/views/environment_checks.xml
-
20galicea_environment_checkup/views/views.xml
-
1galicea_git/README.md
-
5galicea_git/__init__.py
-
48galicea_git/__manifest__.py
-
3galicea_git/controllers/__init__.py
-
86galicea_git/controllers/main.py
-
12galicea_git/data/config.xml
-
63galicea_git/http_chunked_fix.py
-
4galicea_git/models/__init__.py
-
42galicea_git/models/config_settings.py
-
105galicea_git/models/repository.py
-
3galicea_git/security/ir.model.access.csv
-
47galicea_git/security/security.xml
-
BINgalicea_git/static/description/icon.png
-
BINgalicea_git/static/description/images/config_screenshot.png
-
BINgalicea_git/static/description/images/console_screenshot.png
-
BINgalicea_git/static/description/images/create_screenshot.png
-
19galicea_git/static/description/index.html
-
37galicea_git/system_checks.py
-
71galicea_git/views/views.org.xml
-
43galicea_git/views/views.xml
-
1galicea_git_oauth/README.md
-
4galicea_git_oauth/__init__.py
-
21galicea_git_oauth/__manifest__.py
-
1galicea_git_oauth/controllers/__init__.py
-
14galicea_git_oauth/controllers/ext_git_main.py
-
1galicea_git_oauth/models/__init__.py
-
24galicea_git_oauth/models/ext_repository.py
-
5galicea_openapi/__init__.py
-
33galicea_openapi/__manifest__.py
-
4galicea_openapi/controllers/__init__.py
-
56galicea_openapi/controllers/api.py
-
22galicea_openapi/doc/helloworld.py
-
41galicea_openapi/doc/test1.py
-
3galicea_openapi/models/__init__.py
-
52galicea_openapi/openapi.py
-
2galicea_openapi/security/ir.model.access.csv
-
BINgalicea_openapi/static/description/icon.png
-
1galicea_openid_connect/__init__.py
-
71galicea_openid_connect/__manifest__.py
-
51galicea_openid_connect/models/client.py
-
45galicea_openid_connect/models/config_parameter.py
-
33galicea_openid_connect/security/__init__.py
-
24galicea_openid_connect/system_checks.py
-
16galicea_openid_connect/views/views.xml
-
30galicea_toolset/README.md
-
1galicea_toolset/__init__.py
-
20galicea_toolset/__manifest__.py
-
1galicea_toolset/static/src/js/.#one2many_flexible_widget.js
-
38galicea_toolset/static/src/js/client_actions.js
-
49galicea_toolset/static/src/js/iframe_widget.js
-
68galicea_toolset/static/src/js/one2many_flexible_widget.js
-
16galicea_toolset/utils.py
-
11galicea_toolset/views/data.xml
@ -1 +0,0 @@ |
|||
Base menu for Odoo Galicea Ecosystem |
@ -1,2 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
@ -1,23 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
{ |
|||
'name': "Base menu for Odoo Galicea Ecosystem", |
|||
|
|||
'summary': """ |
|||
Menu only |
|||
""", |
|||
|
|||
'author': "Jurek Wawro", |
|||
'maintainer': "Galicea", |
|||
'website': "http://galicea.pl", |
|||
|
|||
'category': 'Technical Settings', |
|||
'version': '12.0.1.0', |
|||
|
|||
'depends': ['web',], |
|||
|
|||
'data': [ |
|||
'views/base_menu.xml', |
|||
], |
|||
|
|||
'installable': True |
|||
} |
@ -1,6 +0,0 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<menuitem name="Galicea" id="galicea_admin_menu" |
|||
parent="base.menu_administration" groups="base.group_erp_manager" /> |
|||
|
|||
</odoo> |
@ -1 +0,0 @@ |
|||
[See add-on page on odoo.com](https://apps.odoo.com/apps/modules/10.0/galicea_environment_checkup/) |
@ -1,9 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import models |
|||
|
|||
from .environment_checkup.custom import custom_check |
|||
from .environment_checkup.core import CheckFail, CheckWarning, CheckSuccess |
|||
|
|||
from . import controllers |
|||
|
@ -1,32 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
{ |
|||
'name': "Galicea Environment Check-up", |
|||
|
|||
'summary': """ |
|||
Programmatically validate environment, including internal and external |
|||
dependencies""", |
|||
|
|||
'author': "Maciej Wawro", |
|||
'maintainer': "Galicea", |
|||
'website': "http://galicea.pl", |
|||
|
|||
'category': 'Technical Settings', |
|||
'version': '12.0.1.0', |
|||
|
|||
'depends': ['web','galicea_base',], |
|||
|
|||
'data': [ |
|||
'views/data.xml', |
|||
'views/views.xml', |
|||
'views/environment_checks.xml' |
|||
], |
|||
|
|||
'qweb': ['static/src/xml/templates.xml'], |
|||
|
|||
'images': [ |
|||
'static/description/images/custom_screenshot.png', |
|||
'static/description/images/dependencies_screenshot.png' |
|||
], |
|||
|
|||
'installable': True |
|||
} |
@ -1,3 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import dashboard |
@ -1,26 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from odoo import http |
|||
from odoo.exceptions import AccessError |
|||
from odoo.http import request |
|||
|
|||
from ..environment_checkup.runtime import all_installed_checks, display_data |
|||
from ..environment_checkup.core import CheckResult |
|||
|
|||
class Dashboard(http.Controller): |
|||
@http.route('/galicea_environment_checkup/data', type='json', auth='user') |
|||
def data(self, request, **kw): |
|||
if not request.env.user.has_group('base.group_erp_manager'): |
|||
raise AccessError("Access Denied") |
|||
|
|||
checks = all_installed_checks(request.env) |
|||
response = display_data(request.env, checks) |
|||
|
|||
priority = { |
|||
CheckResult.FAIL: 0, |
|||
CheckResult.WARNING: 1, |
|||
CheckResult.SUCCESS: 2 |
|||
} |
|||
response.sort(key=lambda res: (priority[res['result']], res['module'])) |
|||
|
|||
return response |
@ -1,4 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import core |
|||
from . import custom |
@ -1,49 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import logging |
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
class CheckResult(object): |
|||
SUCCESS = 'success' |
|||
WARNING = 'warning' |
|||
FAIL = 'fail' |
|||
|
|||
def __init__(self, result, message, details = None): |
|||
super(CheckResult, self).__init__() |
|||
|
|||
self.result = result |
|||
self.message = message |
|||
self.details = details |
|||
|
|||
class CheckSuccess(CheckResult): |
|||
def __init__(self, message, **kwargs): |
|||
super(CheckSuccess, self).__init__(CheckResult.SUCCESS, message, **kwargs) |
|||
|
|||
class CheckIssue(CheckResult, Exception): |
|||
def __init__(self, result, message, **kwargs): |
|||
Exception.__init__(self, message) |
|||
CheckResult.__init__(self, result, message, **kwargs) |
|||
|
|||
class CheckFail(CheckIssue): |
|||
def __init__(self, message, **kwargs): |
|||
super(CheckFail, self).__init__(CheckResult.FAIL, message, **kwargs) |
|||
|
|||
class CheckWarning(CheckIssue): |
|||
def __init__(self, message, **kwargs): |
|||
super(CheckWarning, self).__init__(CheckResult.WARNING, message, **kwargs) |
|||
|
|||
class Check(object): |
|||
def __init__(self, module): |
|||
self.module = module |
|||
|
|||
def run(self, env): |
|||
try: |
|||
return self._run(env) |
|||
except CheckIssue as issue: |
|||
return issue |
|||
except Exception as ex: |
|||
_logger.exception(ex) |
|||
return CheckFail('Check failed when processing: {}'.format(ex)) |
|||
|
|||
def _run(self, env): |
|||
raise NotImplementedError('Should be overriden by the subclass') |
@ -1,30 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import collections |
|||
|
|||
from .core import Check |
|||
|
|||
custom_checks_per_module = collections.defaultdict(list) |
|||
|
|||
class CustomCheck(Check): |
|||
def __init__(self, module, func): |
|||
super(CustomCheck, self).__init__(module) |
|||
self.func = func |
|||
|
|||
def _run(self, env): |
|||
return self.func(env) |
|||
|
|||
def custom_check(func): |
|||
try: |
|||
module = func.__module__.split('.')[2] |
|||
except IndexError: |
|||
module = '' |
|||
|
|||
custom_checks_per_module[module].append( |
|||
CustomCheck(module=module, func=func) |
|||
) |
|||
|
|||
return func |
|||
|
|||
def get_checks_for_module(module_name): |
|||
return custom_checks_per_module[module_name] |
@ -1,183 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import subprocess |
|||
import re |
|||
import cgi |
|||
from odoo.modules.module import load_information_from_description_file |
|||
from odoo.tools import which |
|||
|
|||
from .core import Check, CheckSuccess, CheckWarning, CheckFail |
|||
|
|||
class DependencyCheck(Check): |
|||
dependency_type = None |
|||
|
|||
def __init__(self, module, dependency): |
|||
super(DependencyCheck, self).__init__(module) |
|||
self.dependency = dependency |
|||
|
|||
def _dependency_installed(self, env, name): |
|||
raise NotImplementedError('Should be overriden by the subclass') |
|||
|
|||
def _installed_version(self, env, name): |
|||
raise NotImplementedError('Should be overriden by the subclass') |
|||
|
|||
def _details(self): |
|||
if 'install' in self.dependency: |
|||
return 'Install command: <pre>{}</pre>'.format(self.dependency['install']) |
|||
return None |
|||
|
|||
def __has_required_version(self, installed_version, version_expression): |
|||
version_operator = '=' |
|||
version = self.dependency['version'] |
|||
if version[:1] in ['=', '~', '^']: |
|||
version_operator = version[:1] |
|||
version = version[1:] |
|||
elif version[:2] in ['>=']: |
|||
version_operator = version[:2] |
|||
version = version[2:] |
|||
|
|||
# Py3 : map -> list(map |
|||
# https://stackoverflow.com/questions/33717314/attributeerror-map-obejct-has-no-attribute-index-python-3 |
|||
try: |
|||
parsed_version = list(map(int, version.split('.'))) |
|||
except ValueError: |
|||
raise CheckFail( |
|||
'Invalid version expression', |
|||
details = """ |
|||
Allowed expressions are <pre>=x.y.z</pre>, <pre>>=x.y.z</pre>, <pre>^x.z.y</pre>, |
|||
<pre>~x.y.z. Got <pre>{}</pre>""".format(cgi.escape(self.dependency['version'])) |
|||
) |
|||
parsed_installed_version = list(map(int, installed_version.split('.'))) |
|||
|
|||
parsed_version.extend(0 for _ in range(len(parsed_installed_version) - len(parsed_version))) |
|||
parsed_installed_version.extend(0 for _ in range(len(parsed_version) - len(parsed_installed_version))) |
|||
|
|||
if version_operator == '^': |
|||
if parsed_installed_version[:1] != parsed_version[:1]: |
|||
return False |
|||
version_operator = '>=' |
|||
elif version_operator == '~': |
|||
if parsed_installed_version[:2] != parsed_version[:2]: |
|||
return False |
|||
version_operator = '>=' |
|||
|
|||
if version_operator == '>=': |
|||
return tuple(parsed_installed_version) >= tuple(parsed_version) |
|||
elif version_operator == '=': |
|||
return tuple(parsed_installed_version) == tuple(parsed_version) |
|||
|
|||
assert False |
|||
|
|||
def _run(self, env): |
|||
name = self.dependency['name'] |
|||
if not self._dependency_installed(env, name): |
|||
raise CheckFail( |
|||
'Required {} - {} - is not installed.'.format(self.dependency_type, name), |
|||
details=self._details() |
|||
) |
|||
if 'version' in self.dependency: |
|||
version_expression = self.dependency['version'] |
|||
installed_version = self._installed_version(env, name) |
|||
if not self.__has_required_version(installed_version, version_expression): |
|||
raise CheckWarning( |
|||
'Required {} - {} - has version {}, but {} is needed.'.format( |
|||
self.dependency_type, |
|||
name, |
|||
installed_version, |
|||
version_expression |
|||
), |
|||
details=self._details() |
|||
) |
|||
return CheckSuccess( |
|||
'Required {} - {} - is installed.'.format(self.dependency_type, name), |
|||
details=self._details() |
|||
) |
|||
|
|||
class InternalDependencyCheck(DependencyCheck): |
|||
dependency_type = 'Odoo module' |
|||
|
|||
def _dependency_installed(self, env, name): |
|||
return name in env.registry._init_modules |
|||
|
|||
def _installed_version(self, env, name): |
|||
return env['ir.module.module'].sudo().search([('name', '=', name)]).latest_version |
|||
|
|||
class PythonDependencyCheck(DependencyCheck): |
|||
dependency_type = 'Python module' |
|||
|
|||
def _dependency_installed(self, env, name): |
|||
try: |
|||
__import__(name) |
|||
return True |
|||
except ImportError: |
|||
return False |
|||
|
|||
def _installed_version(self, env, name): |
|||
try: |
|||
return __import__(name).__version__ |
|||
except AttributeError: |
|||
raise CheckWarning( |
|||
'Could not detect version of the Python module: {}.'.format(name), |
|||
details=self._details() |
|||
) |
|||
|
|||
class ExternalDependencyCheck(DependencyCheck): |
|||
dependency_type = 'system executable' |
|||
|
|||
def _dependency_installed(self, env, name): |
|||
try: |
|||
which(name) |
|||
return True |
|||
except IOError: |
|||
return False |
|||
|
|||
def _installed_version(self, env, name): |
|||
try: |
|||
exe = which(name) |
|||
out = str(subprocess.check_output([exe, '--version'])) # Py3 str() |
|||
match = re.search('[\d.]+', out) |
|||
if not match: |
|||
raise CheckWarning( |
|||
'Unable to detect version for executable {}'.format(name), |
|||
details="Command {} --version returned <pre>{}</pre>".format(exe, out) |
|||
) |
|||
return match.group(0) |
|||
except subprocess.CalledProcessError as e: |
|||
raise CheckWarning( |
|||
'Unable to detect version for executable {}: {}'.format(name, e), |
|||
details=self._details() |
|||
) |
|||
|
|||
def get_checks_for_module(module_name): |
|||
result = [] |
|||
|
|||
manifest = load_information_from_description_file(module_name) |
|||
manifest_checks = manifest.get('environment_checkup') or {} |
|||
dependencies = manifest_checks.get('dependencies') or {} |
|||
|
|||
for dependency in dependencies.get('python') or []: |
|||
result.append(PythonDependencyCheck(module_name, dependency)) |
|||
for dependency in dependencies.get('external') or []: |
|||
result.append(ExternalDependencyCheck(module_name, dependency)) |
|||
for dependency in dependencies.get('internal') or []: |
|||
result.append(InternalDependencyCheck(module_name, dependency)) |
|||
|
|||
return result |
|||
|
|||
def get_checks_for_module_recursive(module): |
|||
class ModuleDFS(object): |
|||
def __init__(self): |
|||
self.visited_modules = set() |
|||
self.checks = [] |
|||
|
|||
def visit(self, module): |
|||
if module.name in self.visited_modules: |
|||
return |
|||
self.visited_modules.add(module.name) |
|||
self.checks += get_checks_for_module(module.name) |
|||
for module_dependency in module.dependencies_id: |
|||
if module_dependency.depend_id: |
|||
self.visit(module_dependency.depend_id) |
|||
return self |
|||
|
|||
return ModuleDFS().visit(module).checks |
@ -1,24 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import custom, dependencies |
|||
|
|||
def all_installed_checks(env): |
|||
result = [] |
|||
installed_modules = env.registry._init_modules |
|||
for module_name in installed_modules: |
|||
result += custom.get_checks_for_module(module_name) |
|||
result += dependencies.get_checks_for_module(module_name) |
|||
return result |
|||
|
|||
def display_data(env, checks): |
|||
response = [] |
|||
for check in checks: |
|||
result = check.run(env) |
|||
response.append({ |
|||
'module': check.module, |
|||
'message': result.message, |
|||
'details': result.details, |
|||
'result': result.result |
|||
}) |
|||
|
|||
return response |
@ -1 +0,0 @@ |
|||
from . import ext_module |
@ -1,19 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import json |
|||
from odoo import api, fields, models |
|||
|
|||
from ..environment_checkup import dependencies |
|||
from ..environment_checkup.runtime import display_data |
|||
|
|||
class Module(models.Model): |
|||
_inherit = 'ir.module.module' |
|||
|
|||
dependency_checks = fields.Text( |
|||
compute='_compute_dependency_checks' |
|||
) |
|||
|
|||
@api.one |
|||
def _compute_dependency_checks(self): |
|||
checks = dependencies.get_checks_for_module_recursive(self) |
|||
self.dependency_checks = json.dumps(display_data(self.env, checks)) |
Before Width: 80 | Height: 80 | Size: 3.4 KiB |
Before Width: 625 | Height: 198 | Size: 24 KiB |
Before Width: 966 | Height: 755 | Size: 92 KiB |
@ -1,79 +0,0 @@ |
|||
<section class="oe_container"> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_span12"> |
|||
<h2 class="oe_slogan">Galicea Environment Check-up</h2> |
|||
<h3 class="oe_slogan"> |
|||
Programmatically validate Odoo environment, including internal and external dependencies of your add-on |
|||
</h3> |
|||
This add-on allows you to: |
|||
<ul> |
|||
<li>programmatically check software dependencies required by your add-on, as well as inform the Administrator as to how to meet them,</li> |
|||
<li>add custom verification for Odoo instance set-up and inform the Administrator about any inconsistencies.</li> |
|||
</ul> |
|||
<h2>Add-on dependency verification</h2> |
|||
<img class="oe_picture oe_screenshot" src="images/dependencies_screenshot.png" /> |
|||
<h3>How-to</h3> |
|||
Just add <tt>'environment_checkup'</tt> entry to <tt>__manifest__.py</tt>. |
|||
<pre> |
|||
{ |
|||
... |
|||
'environment_checkup': { |
|||
'dependencies': { |
|||
'python': [ |
|||
{ |
|||
'name': 'Crypto', |
|||
'version': '>=2.6.2', |
|||
'install': "pip install 'PyCrypto>=2.6.1'" |
|||
}, |
|||
], |
|||
'external': [ |
|||
{ |
|||
'name': 'wkhtmltopdf', |
|||
'install': "apt install wkhtmltopdf" |
|||
}, |
|||
{ |
|||
'name': 'git', |
|||
'version': '^3.0.0', |
|||
'install': "apt install git" |
|||
} |
|||
], |
|||
'internal': [ |
|||
{ |
|||
'name': 'web', |
|||
'version': '~10.0.1.0' |
|||
} |
|||
] |
|||
} |
|||
} |
|||
} |
|||
</pre> |
|||
<h2>Custom environment verification</h2> |
|||
<img class="oe_picture oe_screenshot" src="images/custom_screenshot.png" /> |
|||
<h3>How-to</h3> |
|||
1. Add the check, e.g. in the <tt>system_checks.py</tt> file: |
|||
<pre> |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import cgi |
|||
from odoo.addons.galicea_environment_checkup import custom_check, CheckSuccess, CheckWarning, CheckFail |
|||
|
|||
@custom_check |
|||
def check_mail(env): |
|||
users_without_emails = env['res.users'].sudo().search([('email', '=', False)]) |
|||
|
|||
if users_without_emails: |
|||
raise CheckWarning( |
|||
'Some users don\'t have their e-mails set up.', |
|||
details='See user <tt>{}</tt>.'.format(cgi.escape(users_without_emails[0].name)) |
|||
) |
|||
|
|||
return CheckSuccess('All users have their e-mails set.') |
|||
</pre> |
|||
2. Make sure it's loaded by <tt>__init__.py</tt> |
|||
<pre> |
|||
# -*- coding: utf-8 -*- |
|||
from . import system_checks |
|||
</pre> |
|||
</div> |
|||
</div> |
|||
</section> |
@ -1,146 +0,0 @@ |
|||
odoo.define('galicea_environment_checkup', function (require) { |
|||
"use strict"; |
|||
|
|||
//var SystrayMenu = require('web.SystrayMenu');
|
|||
//var Model = require('web.Model');
|
|||
|
|||
var AbstractAction = require('web.AbstractAction'); |
|||
var core = require('web.core'); |
|||
//var framework = require('web.framework');
|
|||
var session = require('web.session'); |
|||
//var Widget = require('web.Widget');
|
|||
//////////////////
|
|||
var QWeb = core.qweb; |
|||
//var _t = core._t;
|
|||
|
|||
/* SystrayIcon - nie działa poprawnie ??? |
|||
//https://www.odoo.com/documentation/12.0/reference/javascript_reference.html
|
|||
var Model = require('web.Model'); |
|||
|
|||
var Users = new Model('res.users'); |
|||
|
|||
var SystrayIcon = Widget.extend({ |
|||
tagName: 'li', |
|||
events: { |
|||
"click": "on_click", |
|||
}, |
|||
|
|||
start: function(){ |
|||
this.load(this.all_dashboards); |
|||
return this._super(); |
|||
}, |
|||
|
|||
load: function(dashboards){ |
|||
var self = this; |
|||
var loading_done = new $.Deferred(); |
|||
Users.call('has_group', ['base.group_erp_manager']).then(function(is_admin) { |
|||
if (is_admin) { |
|||
session.rpc('/galicea_environment_checkup/data', {}) |
|||
.then(function (data) { |
|||
var counts = { 'success': 0, 'warning': 0, 'fail': 0 }; |
|||
data.forEach(function (check) { ++counts[check.result]; }); |
|||
|
|||
var result; |
|||
if (counts['fail']) { |
|||
result = 'fail'; |
|||
} else if (counts['warning']) { |
|||
result = 'warning'; |
|||
} else { |
|||
result = 'success'; |
|||
} |
|||
|
|||
self.replaceElement(QWeb.render('GaliceaEnvironmentCheckupIcon', { |
|||
'result': result, |
|||
'count': counts['warning'] + counts['fail'] |
|||
})); |
|||
loading_done.resolve(); |
|||
}); |
|||
} else { |
|||
loading_done.resolve(); |
|||
} |
|||
}); |
|||
|
|||
return loading_done; |
|||
}, |
|||
|
|||
on_click: function (event) { |
|||
event.preventDefault(); |
|||
this.do_action('galicea_environment_checkup.dashboard_action', {clear_breadcrumbs: true}); |
|||
}, |
|||
}); |
|||
|
|||
*/ |
|||
|
|||
/////////////////////////////
|
|||
var Dashboard = AbstractAction.extend({ |
|||
// v.10 var Dashboard = Widget.extend({
|
|||
start: function(){ |
|||
return this.load(this.all_dashboards); |
|||
}, |
|||
|
|||
load: function(dashboards) { |
|||
var self = this; |
|||
var loading_done = new $.Deferred(); |
|||
session.rpc('/galicea_environment_checkup/data', {}) |
|||
.then(function (data) { |
|||
self._replaceElement(QWeb.render('GaliceaEnvironmentCheckupDashboard', {'data': data})); // v.10: self.replaceElement
|
|||
loading_done.resolve(); |
|||
}); |
|||
return loading_done; |
|||
}, |
|||
}); |
|||
|
|||
//!JW - nowa propozycja: core.action_registry.add('galicea_environment_checkup.environment_checkup', Dashboard);
|
|||
core.action_registry.add('galicea_environment_checkup.dashboard', Dashboard); |
|||
////////////////////
|
|||
/* v.10 |
|||
var FormWidget = form_common.AbstractField.extend({ |
|||
init: function() { |
|||
this._super.apply(this, arguments); |
|||
this.set("value", "[]"); |
|||
}, |
|||
|
|||
render_value: function() { |
|||
var data = JSON.parse(this.get('value')); |
|||
if (data.length == 0) { |
|||
this.replaceElement('<div />'); |
|||
return; |
|||
} |
|||
this.replaceElement(QWeb.render('GaliceaEnvironmentCheckupFormWidget', {'data': data})); |
|||
}, |
|||
}); |
|||
|
|||
core.form_widget_registry.add('environment_checks', FormWidget); |
|||
*/ |
|||
var FormView = require('web.FormView'); |
|||
|
|||
var FormWidget = FormView.extend({ |
|||
|
|||
template: "environment_checks", |
|||
|
|||
init: function() { |
|||
this._super.apply(this, arguments); |
|||
this.set("value", "[]"); |
|||
}, |
|||
|
|||
events: { |
|||
}, |
|||
|
|||
render_value: function() { |
|||
var data = JSON.parse(this.get('value')); |
|||
if (data.length == 0) { |
|||
this._replaceElement('<div />'); |
|||
return; |
|||
} |
|||
this._replaceElement(QWeb.render('GaliceaEnvironmentCheckupFormWidget', {'data': data})); |
|||
} |
|||
}); |
|||
|
|||
////////////////////
|
|||
return { |
|||
//!! SystrayIcon: SystrayIcon,
|
|||
Dashboard: Dashboard, |
|||
FormWidget: FormWidget |
|||
}; |
|||
|
|||
}); |
@ -1,108 +0,0 @@ |
|||
odoo.define('galicea_environment_checkup', function(require) { |
|||
"use strict"; |
|||
|
|||
var core = require('web.core'); |
|||
var form_common = require('web.form_common'); |
|||
var Widget = require('web.Widget'); |
|||
var session = require('web.session'); |
|||
var QWeb = core.qweb; |
|||
var SystrayMenu = require('web.SystrayMenu'); |
|||
var Model = require('web.Model'); |
|||
|
|||
var Users = new Model('res.users'); |
|||
|
|||
var SystrayIcon = Widget.extend({ |
|||
tagName: 'li', |
|||
events: { |
|||
"click": "on_click", |
|||
}, |
|||
|
|||
start: function(){ |
|||
this.load(this.all_dashboards); |
|||
return this._super(); |
|||
}, |
|||
|
|||
load: function(dashboards){ |
|||
var self = this; |
|||
var loading_done = new $.Deferred(); |
|||
Users.call('has_group', ['base.group_erp_manager']).then(function(is_admin) { |
|||
if (is_admin) { |
|||
session.rpc('/galicea_environment_checkup/data', {}) |
|||
.then(function (data) { |
|||
var counts = { 'success': 0, 'warning': 0, 'fail': 0 }; |
|||
data.forEach(function (check) { ++counts[check.result]; }); |
|||
|
|||
var result; |
|||
if (counts['fail']) { |
|||
result = 'fail'; |
|||
} else if (counts['warning']) { |
|||
result = 'warning'; |
|||
} else { |
|||
result = 'success'; |
|||
} |
|||
|
|||
self.replaceElement(QWeb.render('GaliceaEnvironmentCheckupIcon', { |
|||
'result': result, |
|||
'count': counts['warning'] + counts['fail'] |
|||
})); |
|||
loading_done.resolve(); |
|||
}); |
|||
} else { |
|||
loading_done.resolve(); |
|||
} |
|||
}); |
|||
|
|||
return loading_done; |
|||
}, |
|||
|
|||
on_click: function (event) { |
|||
event.preventDefault(); |
|||
this.do_action('galicea_environment_checkup.dashboard_action', {clear_breadcrumbs: true}); |
|||
}, |
|||
}); |
|||
|
|||
SystrayMenu.Items.push(SystrayIcon); |
|||
|
|||
var Dashboard = Widget.extend({ |
|||
start: function(){ |
|||
return this.load(this.all_dashboards); |
|||
}, |
|||
|
|||
load: function(dashboards) { |
|||
var self = this; |
|||
var loading_done = new $.Deferred(); |
|||
session.rpc('/galicea_environment_checkup/data', {}) |
|||
.then(function (data) { |
|||
self.replaceElement(QWeb.render('GaliceaEnvironmentCheckupDashboard', {'data': data})); |
|||
loading_done.resolve(); |
|||
}); |
|||
return loading_done; |
|||
}, |
|||
}); |
|||
|
|||
core.action_registry.add('galicea_environment_checkup.dashboard', Dashboard); |
|||
|
|||
var FormWidget = form_common.AbstractField.extend({ |
|||
init: function() { |
|||
this._super.apply(this, arguments); |
|||
this.set("value", "[]"); |
|||
}, |
|||
|
|||
render_value: function() { |
|||
var data = JSON.parse(this.get('value')); |
|||
if (data.length == 0) { |
|||
this.replaceElement('<div />'); |
|||
return; |
|||
} |
|||
this.replaceElement(QWeb.render('GaliceaEnvironmentCheckupFormWidget', {'data': data})); |
|||
}, |
|||
}); |
|||
|
|||
core.form_widget_registry.add('environment_checks', FormWidget); |
|||
|
|||
return { |
|||
SystrayIcon: SystrayIcon, |
|||
Dashboard: Dashboard, |
|||
FormWidget: FormWidget |
|||
}; |
|||
}); |
@ -1,71 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
|
|||
<templates xml:space="preserve"> |
|||
<t t-name="GaliceaEnvironmentCheckupIcon"> |
|||
<li> |
|||
<a href="#" t-att-title="result == 'success' ? 'No system setup issues' : 'Found '+count+' system setup issues'"> |
|||
<t t-if="result == 'success'"> |
|||
<i class="fa fa-check" style="opacity:0.5"></i> |
|||
</t> |
|||
<t t-if="result == 'warning'"> |
|||
<i class="fa fa-exclamation-triangle" style="color: orange"></i> |
|||
</t> |
|||
<t t-if="result == 'fail'"> |
|||
<i class="fa fa-exclamation-circle" style="color: red"></i> |
|||
</t> |
|||
<t t-if="result != 'success'"> |
|||
<span><t t-raw="count" /></span> |
|||
</t> |
|||
</a> |
|||
</li> |
|||
</t> |
|||
|
|||
<t t-name="GaliceaEnvironmentChecks"> |
|||
<div class="row"> |
|||
<t t-foreach="data" t-as="check"> |
|||
<div class="col-md-12"> |
|||
<div style="display: flex; background-color: white; padding: 10px; margin: 10px"> |
|||
<div style="flex-grow: 0; flex-shrink: 0; width:50px; margin-right: 20px"> |
|||
<t t-if="check.result == 'success'"> |
|||
<i class="fa fa-check fa-4x" style="color: green" ></i> |
|||
</t> |
|||
<t t-if="check.result == 'warning'"> |
|||
<i class="fa fa-exclamation-triangle fa-4x" style="color: orange" ></i> |
|||
</t> |
|||
<t t-if="check.result == 'fail'"> |
|||
<i class="fa fa-exclamation-circle fa-4x" style="color: red" ></i> |
|||
</t> |
|||
</div> |
|||
<div style="flex-grow: 1; flex-shrink: 1"> |
|||
Module: <t t-esc="check.module" /> |
|||
<h4><t t-esc="check.message" /></h4> |
|||
<div> |
|||
<t t-raw="check.details" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
</div> |
|||
</t> |
|||
|
|||
<t t-name="GaliceaEnvironmentCheckupDashboard"> |
|||
<div class="container"> |
|||
<div class="row"> |
|||
<div class="col-md-12"> |
|||
<h2>Environment check-up</h2> |
|||
<t t-call="GaliceaEnvironmentChecks"> |
|||
<t t-set="data" t-value="data" /> |
|||
</t> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
|
|||
<t t-name="GaliceaEnvironmentCheckupFormWidget"> |
|||
<h1>Module dependencies</h1> |
|||
<t t-call="GaliceaEnvironmentChecks"> |
|||
<t t-set="data" t-value="data" /> |
|||
</t> |
|||
</t> |
|||
</templates> |
@ -1,9 +0,0 @@ |
|||
<odoo> |
|||
<data> |
|||
<template id="assets_backend" inherit_id="web.assets_backend"> |
|||
<xpath expr="." position="inside"> |
|||
<script src="/galicea_environment_checkup/static/src/js/environment_checkup.js" type="text/javascript" /> |
|||
</xpath> |
|||
</template> |
|||
</data> |
|||
</odoo> |
@ -1,17 +0,0 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<template id="stale_modules"> |
|||
<p>The following modules need to be upgraded:</p> |
|||
<ul> |
|||
<t t-foreach="modules" t-as="module"> |
|||
<li> |
|||
<a t-att-href="'#id={}&view_type=form&model=ir.module.module'.format(module.id)"> |
|||
<t t-esc="module.shortdesc" /> (technical name: <t t-esc="module.name" />; |
|||
version on disk: <strong><t t-esc="module.installed_version" /></strong>; |
|||
version in DB: <strong><t t-esc="module.latest_version" /></strong>) |
|||
</a> |
|||
</li> |
|||
</t> |
|||
</ul> |
|||
</template> |
|||
</odoo> |
@ -1,20 +0,0 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<record id="dashboard_action" model="ir.actions.client"> |
|||
<field name="name">Environment check-up dashboard</field> |
|||
<field name="tag">galicea_environment_checkup.dashboard</field> |
|||
</record> |
|||
<menuitem name="Environment check-up" id="dashboard_menu" |
|||
action="dashboard_action" parent="galicea_base.galicea_admin_menu" groups="base.group_erp_manager" /> |
|||
|
|||
<record id="module_form" model="ir.ui.view"> |
|||
<field name="name">module_form.checks</field> |
|||
<field name="model">ir.module.module</field> |
|||
<field name="inherit_id" ref="base.module_form"/> |
|||
<field name="arch" type="xml"> |
|||
<field name="description_html" position="before"> |
|||
<field name="dependency_checks" widget="environment_checks" /> |
|||
</field> |
|||
</field> |
|||
</record> |
|||
</odoo> |
@ -1 +0,0 @@ |
|||
[See add-on page on odoo.com](https://apps.odoo.com/apps/modules/10.0/galicea_git/) |
@ -1,5 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import controllers |
|||
from . import models |
|||
from . import system_checks |
@ -1,48 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
{ |
|||
'name': "Galicea Git hosting", |
|||
|
|||
'summary': """Git repository hosting and per-user access checking""", |
|||
|
|||
'author': "Maciej Wawro", |
|||
'maintainer': "Galicea", |
|||
'website': "http://galicea.pl", |
|||
|
|||
'category': 'Technical Settings', |
|||
'version': '12.0.0.2', |
|||
|
|||
'depends': ['web', 'galicea_environment_checkup','galicea_base'], |
|||
|
|||
'external_dependencies': { |
|||
'bin': ['git'] |
|||
}, |
|||
|
|||
'data': [ |
|||
'security/security.xml', |
|||
'security/ir.model.access.csv', |
|||
|
|||
'data/config.xml', |
|||
'views/views.xml', |
|||
], |
|||
|
|||
'images': [ |
|||
'static/description/images/create_screenshot.png', |
|||
'static/description/images/config_screenshot.png', |
|||
'static/description/images/console_screenshot.png', |
|||
], |
|||
|
|||
'application': True, |
|||
'installable': True, |
|||
|
|||
'environment_checkup': { |
|||
'dependencies': { |
|||
'external': [ |
|||
{ |
|||
'name': 'git', |
|||
'version': '>=2.1.4', |
|||
'install': "apt install git" |
|||
} |
|||
] |
|||
} |
|||
} |
|||
} |
@ -1,3 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import main |
@ -1,86 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import subprocess, os, io |
|||
|
|||
from odoo import http |
|||
from odoo.tools import config |
|||
import werkzeug |
|||
|
|||
from ..http_chunked_fix import http_input_stream |
|||
|
|||
class Main(http.Controller): |
|||
def authorize(self, request): |
|||
auth = request.httprequest.authorization |
|||
if auth: |
|||
request.session.authenticate(request.session.db, auth.username, auth.password) |
|||
|
|||
@http.route( |
|||
[ |
|||
'/git/<repo>', |
|||
'/git/<repo>/<path:path>', |
|||
], |
|||
auth='public', |
|||
csrf=False |
|||
) |
|||
def git(self, request, repo, **kw): |
|||
self.authorize(request) |
|||
if not request.env.uid or request.env.user.login == 'public': |
|||
return werkzeug.Response( |
|||
headers=[('WWW-Authenticate', 'Basic')], |
|||
status=401 |
|||
) |
|||
|
|||
try: |
|||
repository = request.env['galicea_git.repository'].search( |
|||
[('system_name', '=', repo)] |
|||
) |
|||
except AccessError: |
|||
return werkzeug.Response( |
|||
status=403 |
|||
) |
|||
if not repository.exists(): |
|||
return werkzeug.Response( |
|||
status=404 |
|||
) |
|||
|
|||
http_environment = request.httprequest.environ |
|||
git_env = { |
|||
'REQUEST_METHOD': http_environment['REQUEST_METHOD'], |
|||
'QUERY_STRING': http_environment['QUERY_STRING'], |
|||
'CONTENT_TYPE': request.httprequest.headers.get('Content-Type'), |
|||
'REMOTE_ADDR': http_environment['REMOTE_ADDR'], |
|||
'GIT_PROJECT_ROOT': os.path.join(config['data_dir'], 'git'), |
|||
'GIT_HTTP_EXPORT_ALL': '1', |
|||
'PATH_INFO': http_environment['PATH_INFO'][4:], |
|||
'REMOTE_USER': request.env.user.login |
|||
} |
|||
|
|||
command_env = os.environ.copy() |
|||
for var in git_env: |
|||
command_env[var] = git_env[var] |
|||
|
|||
git = subprocess.Popen( |
|||
['/usr/lib/git-core/git-http-backend'], |
|||
stdin=subprocess.PIPE, |
|||
stdout=subprocess.PIPE, |
|||
stderr=subprocess.PIPE, |
|||
env=command_env, |
|||
shell=True |
|||
) |
|||
stdout, stderr = git.communicate(http_input_stream(request).read()) |
|||
headers_str, body = stdout.split(b"\r\n\r\n", 2) |
|||
|
|||
http_status_code = 200 |
|||
headers = [] |
|||
for header in headers_str.split(b"\r\n"): |
|||
name, value = header.split(b': ', 2) |
|||
if name == 'Status': |
|||
http_code = int(value.split(b' ')[0]) |
|||
else: |
|||
headers.append((name.decode('ascii'), value.decode('ascii'))) |
|||
|
|||
return werkzeug.Response( |
|||
body, |
|||
status = http_status_code, |
|||
headers = headers |
|||
) |
@ -1,12 +0,0 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
|
|||
<record id="config_git_backend_path" model="ir.config_parameter"> |
|||
<field name="key">galicea_git.git_http_backend</field> |
|||
<field name="value">/usr/lib/git-core/git-http-backend</field> |
|||
<field name="group_ids" eval="[(4, ref('galicea_git.group_admin'))]" /> |
|||
</record> |
|||
|
|||
</data> |
|||
</odoo> |
@ -1,63 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import io |
|||
|
|||
# Werkzeug version bundled into odoo doesn't handle this kind of Transfer-Encoding |
|||
# correctly. We copy the fix from https://github.com/pallets/werkzeug/pull/1198/files |
|||
class DechunkedInput(io.RawIOBase): |
|||
"""An input stream that handles Transfer-Encoding 'chunked'""" |
|||
|
|||
def __init__(self, rfile): |
|||
self._rfile = rfile |
|||
self._done = False |
|||
self._len = 0 |
|||
|
|||
def readable(self): |
|||
return True |
|||
|
|||
def read_chunk_len(self): |
|||
try: |
|||
line = self._rfile.readline().decode('latin1') |
|||
_len = int(line.strip(), 16) |
|||
except ValueError: |
|||
raise IOError('Invalid chunk header') |
|||
if _len < 0: |
|||
raise IOError('Negative chunk length not allowed') |
|||
return _len |
|||
|
|||
def readinto(self, buf): |
|||
read = 0 |
|||
while not self._done and read < len(buf): |
|||
if self._len == 0: |
|||
# This is the first chunk or we fully consumed the previous |
|||
# one. Read the next length of the next chunk |
|||
self._len = self.read_chunk_len() |
|||
|
|||
if self._len == 0: |
|||
# Found the final chunk of size 0. The stream is now exhausted, |
|||
# but there is still a final newline that should be consumed |
|||
self._done = True |
|||
|
|||
if self._len > 0: |
|||
# There is data (left) in this chunk, so append it to the |
|||
# buffer. If this operation fully consumes the chunk, this will |
|||
# reset self._len to 0. |
|||
n = min(len(buf), self._len) |
|||
buf[read:read + n] = self._rfile.read(n) |
|||
self._len -= n |
|||
read += n |
|||
|
|||
if self._len == 0: |
|||
# Skip the terminating newline of a chunk that has been fully |
|||
# consumed. This also applies to the 0-sized final chunk |
|||
terminator = self._rfile.readline() |
|||
if terminator not in (b'\n', b'\r\n', b'\r'): |
|||
raise IOError('Missing chunk terminating newline') |
|||
|
|||
return read |
|||
|
|||
def http_input_stream(request): |
|||
if request.httprequest.headers.get('Transfer-Encoding') == 'chunked' \ |
|||
and not request.httprequest.environ.get('wsgi.input_terminated'): |
|||
return DechunkedInput(request.httprequest.environ['wsgi.input']) |
|||
return request.httprequest.stream |
@ -1,4 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import repository |
|||
from . import config_settings |
@ -1,42 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import os |
|||
|
|||
from odoo import models, fields, api |
|||
from odoo.exceptions import ValidationError |
|||
|
|||
class ConfigSettings(models.TransientModel): |
|||
_name = 'galicea_git.config.settings' |
|||
_inherit = 'res.config.settings' |
|||
|
|||
git_http_backend = fields.Char( |
|||
'Absolute path to Git HTTP backend', |
|||
required=True |
|||
) |
|||
git_http_backend_valid = fields.Boolean( |
|||
compute='_compute_git_http_backend_valid' |
|||
) |
|||
|
|||
@api.one |
|||
@api.depends('git_http_backend') |
|||
def _compute_git_http_backend_valid(self): |
|||
self.git_http_backend_valid = self.git_http_backend and os.access(self.git_http_backend, os.X_OK) |
|||
|
|||
@api.one |
|||
def set_params(self): |
|||
self.env['ir.config_parameter'].set_param('galicea_git.git_http_backend', self.git_http_backend) |
|||
|
|||
@api.model |
|||
def get_default_values(self, fields): |
|||
return { |
|||
'git_http_backend': self.env['ir.config_parameter'].get_param('galicea_git.git_http_backend') |
|||
} |
|||
|
|||
@api.multi |
|||
def execute(self): |
|||
self.ensure_one() |
|||
if not self.env.user.has_group('galicea_git.group_admin'): |
|||
raise AccessError("Only Git administrators can change those settings") |
|||
super(ConfigSettings, self.sudo()).execute() |
|||
act_window = self.env.ref('galicea_git.config_settings_action') |
|||
return act_window.read()[0] |
@ -1,105 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import os |
|||
import random |
|||
import shutil |
|||
import string |
|||
import subprocess |
|||
try: |
|||
import git |
|||
except ImportError: |
|||
pass |
|||
|
|||
|
|||
from odoo import models, fields, api, http |
|||
from odoo.exceptions import ValidationError |
|||
from odoo.tools import config, which |
|||
|
|||
class Repository(models.Model): |
|||
_name = 'galicea_git.repository' |
|||
|
|||
state = fields.Selection( |
|||
[('draft', 'Draft'), ('created', 'Created')], |
|||
default='draft' |
|||
) |
|||
|
|||
name = fields.Char('User-friendly name', required=True) |
|||
system_name = fields.Char( |
|||
'Directory name', |
|||
required=True, |
|||
readonly=True, |
|||
index=True, |
|||
states={'draft': [('readonly', False)]} |
|||
) |
|||
collaborator_ids = fields.Many2many( |
|||
'res.users', |
|||
string='Collaborators' |
|||
) |
|||
|
|||
local_directory = fields.Char( |
|||
'Local directory on server', |
|||
compute='_compute_local_directory', |
|||
groups='galicea_git.group_admin' |
|||
) |
|||
url = fields.Char( |
|||
'Clone', |
|||
compute='_compute_url' |
|||
) |
|||
|
|||
@api.one |
|||
@api.depends('system_name') |
|||
def _compute_url(self): |
|||
base_url = http.request.httprequest.host_url if http.request \ |
|||
else env['ir.config_parameter'].get_param('web.base.url') + '/' |
|||
self.url = u'{}git/{}'.format(base_url, self.system_name) |
|||
|
|||
@api.one |
|||
@api.depends('system_name') |
|||
def _compute_local_directory(self): |
|||
if self.system_name: |
|||
self.local_directory = os.path.join(config['data_dir'], 'git', self.system_name) |
|||
|
|||
@api.constrains('system_name') |
|||
def _validate_system_name(self): |
|||
allowed_characters = string.ascii_lowercase + string.digits + '-_' |
|||
if not all(c in allowed_characters for c in self.system_name): |
|||
raise ValidationError( |
|||
'Only lowercase, digits and hyphens (-) are allowed in directory name' |
|||
) |
|||
|
|||
@api.constrains('collaborator_ids') |
|||
def _validate_collaborator_ids(self): |
|||
invalid_collaborators = self.collaborator_ids.filtered(lambda c: not c.has_group('galicea_git.group_collaborator')) |
|||
if invalid_collaborators: |
|||
raise ValidationError( |
|||
'User {} does not have the {} role. Contact your Administrator'.format( |
|||
invalid_collaborators[0].name, |
|||
self.env.ref('galicea_git.group_collaborator').full_name |
|||
) |
|||
) |
|||
|
|||
@api.model |
|||
def create(self, values): |
|||
values['state'] = 'created' |
|||
ret = super(Repository, self).create(values) |
|||
ret.__initialize_repo() |
|||
return ret |
|||
|
|||
@api.multi |
|||
def unlink(selfs): |
|||
directories_to_move = selfs.mapped(lambda r: r.local_directory) |
|||
ret = super(Repository, selfs).unlink() |
|||
for directory in directories_to_move: |
|||
if os.path.exists(directory): |
|||
suffix = ''.join(random.choice(string.ascii_lowercase) for _ in range(8)) |
|||
new_directory = directory + '-deleted-' + suffix |
|||
shutil.move(directory, new_directory) |
|||
|
|||
@api.multi |
|||
def __initialize_repo(self): |
|||
self.ensure_one() |
|||
if os.path.exists(self.local_directory): |
|||
raise ValidationError( |
|||
'Repository {} already exists, choose a different name!'.format(self.system_name) |
|||
) |
|||
subprocess.check_call([which('git'), 'init', '--bare', self.local_directory]) |
@ -1,3 +0,0 @@ |
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
|||
access_repository_collaborator,repository_collaborator,model_galicea_git_repository,galicea_git.group_collaborator,1,0,0,0 |
|||
access_repository_admin,repository_admin,model_galicea_git_repository,galicea_git.group_admin,1,1,1,1 |
@ -1,47 +0,0 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<record id="module_category_git" model="ir.module.category"> |
|||
<field name="name">Git</field> |
|||
</record> |
|||
|
|||
<record id="group_collaborator" model="res.groups"> |
|||
<field name="name">Collaborator</field> |
|||
<field name="category_id" ref="module_category_git" /> |
|||
</record> |
|||
|
|||
<record id="group_admin" model="res.groups"> |
|||
<field name="name">Administrator</field> |
|||
<field name="category_id" ref="module_category_git" /> |
|||
<field name="implied_ids" eval="[(4,ref('group_collaborator'))]" /> |
|||
</record> |
|||
|
|||
<record id="base.group_erp_manager" model="res.groups"> |
|||
<field name="implied_ids" eval="[(4,ref('group_admin'))]" /> |
|||
</record> |
|||
|
|||
<record id="repository_collaborator_access_rule" model="ir.rule"> |
|||
<field name="name">Collaborators can only access repositories they are assigned to</field> |
|||
<field name="model_id" ref="model_galicea_git_repository" /> |
|||
<field name="groups" eval="[(4, ref('group_collaborator'))]"/> |
|||
<field name="domain_force"> |
|||
[('collaborator_ids', 'in', user.id)] |
|||
</field> |
|||
<field eval="1" name="perm_read" /> |
|||
<field eval="0" name="perm_write" /> |
|||
<field eval="0" name="perm_create" /> |
|||
<field eval="0" name="perm_unlink" /> |
|||
</record> |
|||
|
|||
<record id="repository_admin_access_rule" model="ir.rule"> |
|||
<field name="name">Administrators can access any repositories</field> |
|||
<field name="model_id" ref="model_galicea_git_repository" /> |
|||
<field name="groups" eval="[(4, ref('group_admin'))]"/> |
|||
<field name="domain_force"> |
|||
[(1, '=', 1)] |
|||
</field> |
|||
<field eval="1" name="perm_read" /> |
|||
<field eval="0" name="perm_write" /> |
|||
<field eval="0" name="perm_create" /> |
|||
<field eval="0" name="perm_unlink" /> |
|||
</record> |
|||
</odoo> |
Before Width: 80 | Height: 80 | Size: 3.8 KiB |
Before Width: 800 | Height: 354 | Size: 42 KiB |
Before Width: 738 | Height: 359 | Size: 78 KiB |
Before Width: 805 | Height: 273 | Size: 31 KiB |
@ -1,19 +0,0 @@ |
|||
<section class="oe_container"> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_span12"> |
|||
<h2 class="oe_slogan">Galicea Git hosting</h2> |
|||
<h3 class="oe_slogan"> |
|||
Simple Odoo-based HTTP interface for Git repository hosting |
|||
</h3> |
|||
<p> |
|||
This add-on allows you to create Git repositories hosted by Odoo, and add specific Odoo users as collaborators. Only those users will have access to the repository. It requires <tt>git</tt> package, including <tt>git-http-backend</tt>, installed in the system. For Ubuntu/Debian it's enough to call |
|||
<pre>sudo apt install git</pre> |
|||
</p> |
|||
<h3>Creating repositories</h3> |
|||
<img class="oe_picture oe_screenshot" src="images/create_screenshot.png" /> |
|||
<img class="oe_picture oe_screenshot" src="images/config_screenshot.png" /> |
|||
<h3>Interacting with the repository</h3> |
|||
<img class="oe_picture oe_screenshot" src="images/console_screenshot.png" /> |
|||
</div> |
|||
</div> |
|||
</section> |
@ -1,37 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import os |
|||
|
|||
from odoo.addons.galicea_environment_checkup import \ |
|||
custom_check, CheckWarning, CheckSuccess, CheckFail |
|||
from odoo import http |
|||
|
|||
@custom_check |
|||
def check_single_db(env): |
|||
if not http.request: |
|||
raise CheckWarning('Could not detect DB settings.') |
|||
|
|||
dbs = http.db_list(True, http.request.httprequest) |
|||
if len(dbs) == 1: |
|||
return CheckSuccess('Odoo runs in a single-DB mode.') |
|||
|
|||
details = ( |
|||
'<p>Odoo runs in a multi-DB mode, which will cause Git HTTP requests to fail.</p>' |
|||
'<p>Run Odoo with <tt>--dbfilter</tt> or <tt>--database</tt> flag.</p>' |
|||
) |
|||
return CheckFail( |
|||
'Odoo runs in a multi-DB mode.', |
|||
details=details |
|||
) |
|||
|
|||
@custom_check |
|||
def check_http_backend(env): |
|||
backend_path = env['ir.config_parameter'].sudo().get_param( |
|||
'galicea_git.git_http_backend' |
|||
) |
|||
if not os.access(backend_path, os.X_OK): |
|||
raise CheckFail( |
|||
'Git HTTP backend not found', |
|||
details='<a href="http://galicea.mw-odoo:8080/web#action=galicea_git.config_settings_action">Check the configuration here</a>' |
|||
) |
|||
return CheckSuccess('Git HTTP backend was found') |
@ -1,71 +0,0 @@ |
|||
<odoo> |
|||
<data> |
|||
<record id="repository_view_form" model="ir.ui.view"> |
|||
<field name="model">galicea_git.repository</field> |
|||
<field name="arch" type="xml"> |
|||
<form> |
|||
<group> |
|||
<field name="state" invisible="1" /> |
|||
<field name="name" /> |
|||
<field name="system_name" groups="galicea_git.group_admin" /> |
|||
<field name="collaborator_ids" widget="many2many_tags" options="{'no_create': True}" /> |
|||
</group> |
|||
<group class="oe_read_only"> |
|||
<label for="url" /> |
|||
<span style="font-family: monospace">git clone <field name="url" nolabel="True" /></span> |
|||
<field name="local_directory" style="font-family: monospace" /> |
|||
</group> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="repository_view_tree" model="ir.ui.view"> |
|||
<field name="model">galicea_git.repository</field> |
|||
<field name="arch" type="xml"> |
|||
<tree> |
|||
<field name="state" invisible="1" /> |
|||
<field name="name" /> |
|||
<field name="system_name" groups="galicea_git.group_admin" /> |
|||
</tree> |
|||
</field> |
|||
</record> |
|||
|
|||
<act_window id="repository_action" |
|||
name="Git repositories" |
|||
res_model="galicea_git.repository" /> |
|||
|
|||
<record id="config_settings_view_form" model="ir.ui.view"> |
|||
<field name="model">galicea_git.config.settings</field> |
|||
<field name="arch" type="xml"> |
|||
<form string="Git hosting settings" class="oe_form_configuration"> |
|||
<header> |
|||
<button string="Save" type="object" name="execute" class="oe_highlight"/> |
|||
<button string="Cancel" type="object" name="cancel" class="oe_link"/> |
|||
</header> |
|||
<field name="git_http_backend_valid" invisible="1" /> |
|||
<group> |
|||
<label for="git_http_backend" /> |
|||
<span> |
|||
<field name="git_http_backend" nolabel="True" class="oe_inline" style="min-width:300px; margin-right:5px" /> |
|||
<i class="fa fa-check" aria-hidden="true" style="color: green" |
|||
attrs="{'invisible': [('git_http_backend_valid', '=', False)]}" /> |
|||
<i class="fa fa-times" aria-hidden="true" style="color: red" |
|||
attrs="{'invisible': [('git_http_backend_valid', '=', True)]}" /> |
|||
</span> |
|||
</group> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
|
|||
<act_window id="config_settings_action" |
|||
name="Settings" |
|||
res_model="galicea_git.config.settings" |
|||
parent="base.menu_administration" |
|||
view_mode="form" target="inline" /> |
|||
|
|||
<menuitem name="Git hosting" id="git_root_menu" sequence="20" /> |
|||
<menuitem name="Repositories" id="repo_menu" parent="galicea_git.git_root_menu" action="repository_action" sequence="1" /> |
|||
<menuitem name="Settings" id="settings_menu" parent="galicea_git.git_root_menu" action="config_settings_action" sequence="99" |
|||
groups="galicea_git.group_admin" /> |
|||
</data> |
|||
</odoo> |
@ -1,43 +0,0 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data> |
|||
|
|||
<record id="repository_view_form" model="ir.ui.view"> |
|||
<field name="model">galicea_git.repository</field> |
|||
<field name="arch" type="xml"> |
|||
<form> |
|||
<group> |
|||
<field name="state" invisible="1" /> |
|||
<field name="name" /> |
|||
<field name="system_name" groups="galicea_git.group_admin" /> |
|||
<field name="collaborator_ids" widget="many2many_tags" options="{'no_create': True}" /> |
|||
</group> |
|||
<group class="oe_read_only"> |
|||
<label for="url" /> |
|||
<span style="font-family: monospace">git clone <field name="url" nolabel="True" /></span> |
|||
<field name="local_directory" style="font-family: monospace" /> |
|||
</group> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="repository_view_tree" model="ir.ui.view"> |
|||
<field name="model">galicea_git.repository</field> |
|||
<field name="arch" type="xml"> |
|||
<tree> |
|||
<field name="state" invisible="1" /> |
|||
<field name="name" /> |
|||
<field name="system_name" groups="galicea_git.group_admin" /> |
|||
</tree> |
|||
</field> |
|||
</record> |
|||
|
|||
<act_window id="repository_action" |
|||
name="Git repositories" |
|||
res_model="galicea_git.repository" /> |
|||
|
|||
<menuitem name="Repositories" id="repo_menu" parent="galicea_base.galicea_admin_menu" |
|||
action="repository_action" sequence="1" /> |
|||
|
|||
</data> |
|||
</odoo> |
@ -1 +0,0 @@ |
|||
[See add-on page on odoo.com](https://apps.odoo.com/apps/modules/12.0/galicea_git_oauth/) |
@ -1,4 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import models |
|||
from . import controllers |
@ -1,21 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
{ |
|||
'name': "Galicea Git OAuth", |
|||
|
|||
'summary': """ |
|||
Enables Git auth via OAuth token""", |
|||
|
|||
'author': "Maciej Wawro", |
|||
'maintainer': "Galicea", |
|||
'website': "http://galicea.pl", |
|||
|
|||
'category': 'Technical Settings', |
|||
'version': '12.0.1.0', |
|||
|
|||
'depends': ['galicea_git', 'galicea_openid_connect'], |
|||
|
|||
'data': [ |
|||
], |
|||
|
|||
'installable': True |
|||
} |
@ -1 +0,0 @@ |
|||
from . import ext_git_main |
@ -1,14 +0,0 @@ |
|||
from odoo.addons.galicea_git.controllers.main import Main |
|||
|
|||
class ExtMain(Main): |
|||
def authorize(self, req): |
|||
auth = req.httprequest.authorization |
|||
if auth and auth.password == 'bearer': |
|||
access_token = req.httprequest.authorization.username |
|||
token = req.env['galicea_openid_connect.access_token'].sudo().search( |
|||
[('token', '=', access_token)] |
|||
) |
|||
if token: |
|||
req.uid = token.user_id.id |
|||
return |
|||
super(ExtMain, self).authorize(req) |
@ -1 +0,0 @@ |
|||
from . import ext_repository |
@ -1,24 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from urllib.parse import urlparse |
|||
from odoo import models |
|||
|
|||
class Repository(models.Model): |
|||
_inherit = 'galicea_git.repository' |
|||
|
|||
def authenticated_url(self, client): |
|||
""" |
|||
@param application galicea_openid.application""" |
|||
|
|||
token = self.env['galicea_openid_connect.access_token'].sudo().retrieve_or_create( |
|||
self.env.user.id, |
|||
client.id |
|||
) |
|||
unauthenticated_url = self.url |
|||
url_parts = urlparse(unauthenticated_url) |
|||
return '{}://{}:bearer@{}{}'.format( |
|||
url_parts.scheme, |
|||
token.token, |
|||
url_parts.netloc, |
|||
url_parts.path, |
|||
) |
@ -1,5 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
#from . import models |
|||
from . import controllers |
|||
|
@ -1,33 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
{ |
|||
'name': "openapi", |
|||
|
|||
'summary': """ |
|||
Odoo Opnapi |
|||
UWAGA! Obecnie dekorator apiroute ma ograniczoną funkcjonalność. |
|||
M.in. tylko jeden URL |
|||
controllers/api.py zawiera przykład wykorzystania - |
|||
pod adresem /oapi/api zwraca dokumentację w JSON |
|||
""", |
|||
|
|||
'description': """ |
|||
|
|||
""", |
|||
|
|||
'author': 'Jerzy Wawro', |
|||
'maintainer': "Galicea", |
|||
'website': "http://www.galicea.pl", |
|||
'category': 'Tools', |
|||
'version': '12.0.0.1', |
|||
|
|||
'depends': [ |
|||
], |
|||
'external_dependencies': { |
|||
'python': [ 'fastapi', 'pydantic', 'starlette' ] |
|||
}, |
|||
'data': [ |
|||
], |
|||
'application': True, |
|||
'installable': True, |
|||
|
|||
} |
@ -1,4 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import api |
|||
|
@ -1,56 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import json |
|||
|
|||
from fastapi.openapi.docs import get_swagger_ui_html |
|||
|
|||
from odoo import http, _ |
|||
from ..openapi import apiroute |
|||
from ..openapi import oapi |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
class OpenApiTest(http.Controller): |
|||
|
|||
|
|||
@http.route(['/oapi/tst1',], type='http', auth="user", website=True) |
|||
def tst1(self, **kw): |
|||
return "tst1" |
|||
|
|||
@oapi.get('/oapi/tst2') |
|||
@http.route(['/oapi/tst2',], type='http', auth="user", website=True) |
|||
def tst2(self): |
|||
return 'ok test2' |
|||
|
|||
@oapi.api_route('/oapi/tst3') |
|||
@http.route(['/oapi/tst3',], type='http', auth="user", website=True) |
|||
def tst3(self, par1="abc"): |
|||
return par1 |
|||
|
|||
|
|||
@oapi.api_route('/oapi/tst4') |
|||
@http.route(['/oapi/tst4', ], type='http', auth="user", website=True) |
|||
def tst4(self,par1="444"): |
|||
return par1 |
|||
|
|||
|
|||
@apiroute('/oapi/tst5') |
|||
def tst5(self, par1="555"): |
|||
return par1 |
|||
|
|||
@http.route(['/oapi/api',], type='http', auth="user", website=True) |
|||
def api(self, **kw): |
|||
return json.dumps(oapi.openapi()) |
|||
# wynik możesz skopiować do https://editor.swagger.io/ |
|||
|
|||
@http.route(['/oapi/docs',], type='http', auth="user", website=True) |
|||
def api_UI(self, **kw): |
|||
response = get_swagger_ui_html(openapi_url = '/oapi/api', title = 'tytuł') |
|||
return response.body |
|||
|
|||
|
|||
|
|||
|
|||
|
@ -1,22 +0,0 @@ |
|||
# pip install fastapi |
|||
# pip install email-validator |
|||
# pip install pydantic |
|||
# pip install starlette |
|||
# pip install uvicorn |
|||
|
|||
import uvicorn |
|||
from fastapi import FastAPI |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
@app.get("/") |
|||
def read_root(): |
|||
return {"Hello": "World"} |
|||
|
|||
def run_server(): |
|||
uvicorn.run(app) |
|||
|
|||
if __name__ == '__main__': |
|||
uvicorn.run(app, #'server:app', |
|||
host='127.0.0.1', port=8000, reload=True) |
@ -1,41 +0,0 @@ |
|||
# pip install fastapi |
|||
# pip install email-validator |
|||
# pip install pydantic |
|||
# pip install starlette |
|||
# pip install uvicorn |
|||
|
|||
import uvicorn |
|||
from fastapi import FastAPI |
|||
from fastapi.openapi.utils import get_openapi |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
@app.get("/items/") |
|||
async def read_items(): |
|||
return [{"name": "Foo"}] |
|||
|
|||
|
|||
def custom_openapi(): |
|||
if app.openapi_schema: |
|||
return app.openapi_schema |
|||
openapi_schema = get_openapi( |
|||
title="Custom title", |
|||
version="2.5.0", |
|||
description="This is a very custom OpenAPI schema", |
|||
routes=app.routes, |
|||
) |
|||
openapi_schema["info"]["x-logo"] = { |
|||
"url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" |
|||
} |
|||
app.openapi_schema = openapi_schema |
|||
return app.openapi_schema |
|||
|
|||
|
|||
app.openapi = custom_openapi |
|||
|
|||
|
|||
if __name__ == '__main__': |
|||
print("see http://127.0.0.1:8000/docs") |
|||
uvicorn.run(app, #'server:app', |
|||
host='127.0.0.1', port=8000, reload=True) |
@ -1,3 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
|
@ -1,52 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
|
|||
import functools |
|||
from fastapi import FastAPI |
|||
from fastapi.openapi.utils import get_openapi |
|||
|
|||
|
|||
|
|||
def custom_openapi(): |
|||
if oapi.openapi_schema: |
|||
return oapi.openapi_schema |
|||
openapi_schema = get_openapi( |
|||
title="Custom title", |
|||
version="2.5.0", |
|||
description="This is a very custom OpenAPI schema", |
|||
routes=oapi.routes, |
|||
) |
|||
openapi_schema["info"]["x-logo"] = { |
|||
"url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" |
|||
} |
|||
oapi.openapi_schema = openapi_schema |
|||
return oapi.openapi_schema |
|||
|
|||
oapi = FastAPI() |
|||
oapi.openapi = custom_openapi |
|||
|
|||
def apiroute(route=None, **kw): |
|||
|
|||
routing = kw.copy() |
|||
def apidecorator(f): |
|||
if route: |
|||
if isinstance(route, list): |
|||
routes = route |
|||
else: |
|||
routes = [route] |
|||
routing['routes'] = routes |
|||
|
|||
@functools.wraps(f) |
|||
def response_wrap(*args, **kw): |
|||
response = f(*args, **kw) |
|||
return response |
|||
|
|||
oapi.add_api_route(routes[0], f, include_in_schema=True) |
|||
response_wrap.routing = routing |
|||
response_wrap.original_func = f |
|||
return response_wrap |
|||
|
|||
return apidecorator |
|||
|
|||
|
|||
# |
@ -1,2 +0,0 @@ |
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
|||
access_galicea_openapi,galicea_openapi,model_galicea_openapi_openapi_script,galicea_openapi.script,1,1,1,0 |
Before Width: 128 | Height: 128 | Size: 10 KiB |
@ -1,51 +1,38 @@ |
|||
# -*- coding: utf-8 -*- |
|||
{ |
|||
'name': "Galicea OpenID Connect Provider", |
|||
|
|||
'summary': """OpenID Connect Provider and OAuth2 resource server""", |
|||
|
|||
'author': "Maciej Wawro", |
|||
'maintainer': "Galicea", |
|||
'website': "http://galicea.pl", |
|||
|
|||
'category': 'Technical Settings', |
|||
'version': '12.0.0.0', |
|||
|
|||
'depends': ['web', 'galicea_environment_checkup', 'galicea_base' ], |
|||
|
|||
'external_dependencies': { |
|||
'python': ['jwcrypto', 'cryptography'] |
|||
}, |
|||
|
|||
'data': [ |
|||
'security/security.xml', |
|||
'security/ir.model.access.csv', |
|||
# 'security/init.yml', |
|||
'security/init.xml', |
|||
'views/views.xml', |
|||
'views/templates.xml' |
|||
"name": "Galicea OpenID Connect Provider", |
|||
"summary": """OpenID Connect Provider and OAuth2 resource server""", |
|||
"author": "Maciej Wawro, Nicolas JEUDY", |
|||
"maintainer": "nj.0k.io, Galicea", |
|||
"website": "https://nj.0k.io", |
|||
"category": "Technical Settings", |
|||
"version": "14.0.0.0", |
|||
"depends": ["web"], |
|||
"external_dependencies": {"python": ["jwcrypto", "cryptography"]}, |
|||
"data": [ |
|||
"security/security.xml", |
|||
"security/ir.model.access.csv", |
|||
# 'security/init.yml', |
|||
"security/init.xml", |
|||
"views/views.xml", |
|||
"views/templates.xml", |
|||
], |
|||
|
|||
'environment_checkup': { |
|||
'dependencies': { |
|||
'python': [ |
|||
"environment_checkup": { |
|||
"dependencies": { |
|||
"python": [ |
|||
{"name": "jwcrypto", "install": "pip install 'jwcrypto==0.5.0'"}, |
|||
{ |
|||
'name': 'jwcrypto', |
|||
'install': "pip install 'jwcrypto==0.5.0'" |
|||
"name": "cryptography", |
|||
"version": ">=2.3", |
|||
"install": "pip install 'cryptography>=2.3'", |
|||
}, |
|||
{ |
|||
'name': 'cryptography', |
|||
'version': '>=2.3', |
|||
'install': "pip install 'cryptography>=2.3'" |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
|
|||
'images': [ |
|||
'static/description/images/master_screenshot.png', |
|||
'static/description/images/client_screenshot.png', |
|||
'static/description/images/login_screenshot.png', |
|||
'static/description/images/error_screenshot.png' |
|||
] |
|||
"images": [ |
|||
"static/description/images/master_screenshot.png", |
|||
"static/description/images/client_screenshot.png", |
|||
"static/description/images/login_screenshot.png", |
|||
"static/description/images/error_screenshot.png", |
|||
], |
|||
} |
@ -1,23 +1,36 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from .. import random_tokens |
|||
|
|||
try: |
|||
from jwcrypto import jwk |
|||
except ImportError: |
|||
pass |
|||
|
|||
|
|||
def init_keys(IrConfigParameter): |
|||
keys = { |
|||
'galicea_openid_connect.authorization_code_jwk': lambda: \ |
|||
jwk.JWK.generate(kty='oct', size=256, kid=random_tokens.alpha_numeric(16), use='sig', alg='HS256').export(), |
|||
'galicea_openid_connect.id_token_jwk': lambda: \ |
|||
jwk.JWK.generate(kty='RSA', size=2054, kid=random_tokens.alpha_numeric(16), use='sig', alg='RS256').export() |
|||
"galicea_openid_connect.authorization_code_jwk": lambda: jwk.JWK.generate( |
|||
kty="oct", |
|||
size=256, |
|||
kid=random_tokens.alpha_numeric(16), |
|||
use="sig", |
|||
alg="HS256", |
|||
).export(), |
|||
"galicea_openid_connect.id_token_jwk": lambda: jwk.JWK.generate( |
|||
kty="RSA", |
|||
size=2054, |
|||
kid=random_tokens.alpha_numeric(16), |
|||
use="sig", |
|||
alg="RS256", |
|||
).export(), |
|||
} |
|||
|
|||
for key, gen in keys.iteritems(): |
|||
if not IrConfigParameter.search([('key', '=', key)]): |
|||
IrConfigParameter.create({ |
|||
'key': key, |
|||
'value': gen(), |
|||
'group_ids': [(4, IrConfigParameter.env.ref('base.group_erp_manager').id)] |
|||
}) |
|||
if not IrConfigParameter.search([("key", "=", key)]): |
|||
IrConfigParameter.create( |
|||
{ |
|||
"key": key, |
|||
"value": gen(), |
|||
} |
|||
) |
@ -1,24 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from odoo.addons.galicea_environment_checkup import \ |
|||
custom_check, CheckWarning, CheckSuccess, CheckFail |
|||
|
|||
from odoo import http |
|||
|
|||
@custom_check |
|||
def check_single_db(env): |
|||
if not http.request: |
|||
raise CheckWarning('Could not detect DB settings.') |
|||
|
|||
dbs = http.db_list(True, http.request.httprequest) |
|||
if len(dbs) == 1: |
|||
return CheckSuccess('Odoo runs in a single-DB mode.') |
|||
|
|||
details = ( |
|||
'<p>Odoo runs in a multi-DB mode, which will cause API request routing to fail.</p>' |
|||
'<p>Run Odoo with <tt>--dbfilter</tt> or <tt>--database</tt> flag.</p>' |
|||
) |
|||
return CheckFail( |
|||
'Odoo runs in a multi-DB mode.', |
|||
details=details |
|||
) |
@ -1,30 +0,0 @@ |
|||
Widgets |
|||
======= |
|||
|
|||
<field name="url_field" widget="iframe" style="width: 100%" iframe_style="width: 100%" /> |
|||
|
|||
Creates an iframe with ``url_field`` value as a source. |
|||
|
|||
<field name="article_ids" widget="one2many_flexible" click_target="current" /> |
|||
|
|||
Allows changing the target for the item click action. |
|||
|
|||
Functions |
|||
========= |
|||
odoo.addons.galicea_toolset.utils.get_base_url(env) |
|||
|
|||
Client actions |
|||
============== |
|||
@api.multi |
|||
|
|||
def button_action(self): |
|||
|
|||
return { |
|||
|
|||
'type': 'ir.actions.client', |
|||
|
|||
'tag': 'galicea_toolset.open_edit_dialog', |
|||
|
|||
'params': { 'res_id': <id>, 'res_model': <model>, 'title': <title>} |
|||
|
|||
}; |
@ -1 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
@ -1,20 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
{ |
|||
'name': "galicea toolset", |
|||
|
|||
'summary': """ |
|||
A couple of small convenience widgets and functions""", |
|||
|
|||
'author': "Maciej Wawro", |
|||
'maintainer': "Galicea", |
|||
'website': "http://www.galicea.pl", |
|||
|
|||
'category': 'Technical Settings', |
|||
'version': '12.0.0.1', |
|||
|
|||
'depends': ['base'], |
|||
|
|||
'data': [ |
|||
'views/data.xml' |
|||
], |
|||
} |
@ -1 +0,0 @@ |
|||
jurek@jurek.15022 |
@ -1,38 +0,0 @@ |
|||
odoo.define('galicea_toolset.client_actions', function(require) { |
|||
var Widget = require('web.Widget'); |
|||
var core = require('web.core'); |
|||
var common = require('web.form_common'); |
|||
var ActionManager = require('web.ActionManager'); |
|||
|
|||
var OpenEditDialogAction = Widget.extend({ |
|||
init: function(parent, context) { |
|||
this._super.apply(this, arguments); |
|||
this.context = context; |
|||
if (parent instanceof ActionManager) { |
|||
this.am = parent; |
|||
} |
|||
}, |
|||
|
|||
start: function () { |
|||
var params = this.context.params; |
|||
|
|||
var popup = new common.FormViewDialog(self, { |
|||
title: params.title, |
|||
res_model: params.res_model, |
|||
res_id: params.res_id, |
|||
}).open(); |
|||
popup.on('closed', this, function() { |
|||
this.am && this.am.history_back(); |
|||
}); |
|||
}, |
|||
}); |
|||
|
|||
core.action_registry.add( |
|||
'galicea_toolset.open_edit_dialog', |
|||
OpenEditDialogAction |
|||
); |
|||
|
|||
return { |
|||
open_edit_dialog_action: OpenEditDialogAction, |
|||
}; |
|||
}); |
@ -1,49 +0,0 @@ |
|||
odoo.define('pwste_epub.iframe_widget', function(require) { |
|||
|
|||
var AbstractField = require('web.AbstractField'); |
|||
var fieldRegistry = require('web.field_registry'); |
|||
|
|||
|
|||
|
|||
var core = require('web.core'); |
|||
var Widget= require('web.Widget'); |
|||
var widgetRegistry = require('web.widget_registry'); |
|||
var FieldManagerMixin = require('web.FieldManagerMixin'); |
|||
|
|||
var IFrameWidget = AbstractField.extend({ |
|||
|
|||
init: function () { |
|||
this._super.apply(this, arguments); |
|||
// this.set("value", "");
|
|||
}, |
|||
|
|||
_renderReadonly: function() { |
|||
window.widget=this; |
|||
this.$el.html( |
|||
$('<iframe>', { |
|||
src: this.value || 'about:blank', |
|||
style: this.attrs.iframe_style |
|||
}) |
|||
); |
|||
if (this.attrs.new_window_label && this.value) { |
|||
this.$el.prepend( |
|||
$('<a>', { |
|||
href: this.value, |
|||
target: '_blank', |
|||
style: 'float:right; margin-bottom: 10px', |
|||
'class': 'btn btn-primary', |
|||
}).html('<i class="fa fa-external-link-square" aria-hidden="true"></i> Otwórz w nowym oknie') |
|||
) |
|||
} |
|||
}, |
|||
}); |
|||
|
|||
fieldRegistry.add( |
|||
'iframe', IFrameWidget |
|||
); |
|||
|
|||
return { |
|||
IFrameWidget: IFrameWidget, |
|||
}; |
|||
|
|||
}); |
@ -1,68 +0,0 @@ |
|||
odoo.define('galicea_toolset.one2many_flexible_widget', function(require) { |
|||
var core = require('web.core'); |
|||
/* |
|||
var view_dialogs = require('web.view_dialogs'), |
|||
relational_fields = require('web.relational_fields'), |
|||
rpc = require('web.rpc'), |
|||
field_registry = require('web.field_registry');*/ |
|||
|
|||
var form_relational = require('web.form_relational'); |
|||
|
|||
/* var X2ManyList = form_relational.X2ManyList; |
|||
var ListView = require('web.ListView'); |
|||
var FieldOne2Many = field_registry.get('one2many'); |
|||
var FieldOne2Many = relational_fields.FieldOne2Many; |
|||
|
|||
|
|||
var FormController = require('web.FormController'); |
|||
*/ |
|||
/* |
|||
ListView.include({ |
|||
do_activate_record: function (index, id, dataset, view) { |
|||
var action = this.ViewManager.action; |
|||
if (!action || !action.context || !action.context.open_formview) |
|||
return this._super(index, id, dataset, view); |
|||
do_action(this, id, action.context); |
|||
} |
|||
}); |
|||
|
|||
|
|||
var One2ManyListView = core.one2many_view_registry.get('list'); |
|||
*/ |
|||
|
|||
var One2ManyFlexibleListView = form_relational.One2ManyListView.extend({ |
|||
do_activate_record: function(index, id) { |
|||
var self = this; |
|||
if (!this.x2m.get("effective_readonly")) { |
|||
this._super.apply(this, arguments); |
|||
return; |
|||
} |
|||
|
|||
this.do_action({ |
|||
'type': 'ir.actions.act_window', |
|||
'views': [[false, 'form']], |
|||
'res_model': self.x2m.field.relation, |
|||
'res_id': id, |
|||
'target': self.x2m.node.attrs.click_target || 'current', |
|||
}); |
|||
} |
|||
}); |
|||
|
|||
var FieldOne2Many = core.form_widget_registry.get('one2many'); |
|||
|
|||
var FieldOne2ManyFlexible = FieldOne2Many.extend({ |
|||
init: function() { |
|||
this._super.apply(this, arguments); |
|||
this.x2many_views = { |
|||
kanban: core.view_registry.get('one2many_kanban'), |
|||
list: One2ManyFlexibleListView, |
|||
}; |
|||
}, |
|||
}); |
|||
|
|||
core.form_widget_registry.add('one2many_flexible', FieldOne2ManyFlexible); |
|||
|
|||
return { |
|||
FieldOne2ManyFlexible: FieldOne2ManyFlexible, |
|||
}; |
|||
}); |
@ -1,16 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from odoo import http |
|||
|
|||
def get_base_url(env): |
|||
""" |
|||
Better host name detection |
|||
@param env odoo.api.Environment""" |
|||
|
|||
if http.request: |
|||
# Preferuj nazwę hosta, która została użyta do tego zapytania |
|||
return http.request.httprequest.host_url |
|||
else: |
|||
# Jeśli nie jesteśmy wewnątrz zapytania HTTP, zwróć domenę ostatnio użytą |
|||
# przez admina do zalogowania |
|||
return env['ir.config_parameter'].get_param('web.base.url') + '/' |
@ -1,11 +0,0 @@ |
|||
<odoo> |
|||
<data> |
|||
<template id="assets_backend" inherit_id="web.assets_backend"> |
|||
<xpath expr="." position="inside"> |
|||
<script src="/galicea_toolset/static/src/js/iframe_widget.js" type="text/javascript" /> |
|||
<script src="/galicea_toolset/static/src/js/one2many_flexible_widget.js" type="text/javascript" /> |
|||
<script src="/galicea_toolset/static/src/js/client_actions.js" type="text/javascript" /> |
|||
</xpath> |
|||
</template> |
|||
</data> |
|||
</odoo> |