jurek 5 years ago
parent
commit
cecac7869b
  1. 1
      galicea_base/README.md
  2. 2
      galicea_base/__init__.py
  3. 23
      galicea_base/__manifest__.py
  4. 6
      galicea_base/views/base_menu.xml
  5. 6
      galicea_environment_checkup/__init__.py
  6. 4
      galicea_environment_checkup/__manifest__.py
  7. 4
      galicea_environment_checkup/environment_checkup/__init__.py
  8. 2
      galicea_environment_checkup/environment_checkup/custom.py
  9. 10
      galicea_environment_checkup/environment_checkup/dependencies.py
  10. 2
      galicea_environment_checkup/environment_checkup/runtime.py
  11. 54
      galicea_environment_checkup/static/src/js/environment_checkup.js
  12. 108
      galicea_environment_checkup/static/src/js/environment_checkup10.js
  13. 6
      galicea_environment_checkup/static/src/xml/templates.xml
  14. 2
      galicea_environment_checkup/views/views.xml
  15. 4
      galicea_git/__manifest__.py
  16. 8
      galicea_git/controllers/main.py
  17. 3
      galicea_git/data/config.xml
  18. 7
      galicea_git/models/repository.py
  19. 71
      galicea_git/views/views.org.xml
  20. 35
      galicea_git/views/views.xml
  21. 5
      galicea_openapi/__init__.py
  22. 33
      galicea_openapi/__manifest__.py
  23. 4
      galicea_openapi/controllers/__init__.py
  24. 56
      galicea_openapi/controllers/api.py
  25. 22
      galicea_openapi/doc/helloworld.py
  26. 41
      galicea_openapi/doc/test1.py
  27. 3
      galicea_openapi/models/__init__.py
  28. 52
      galicea_openapi/openapi.py
  29. 2
      galicea_openapi/security/ir.model.access.csv
  30. BIN
      galicea_openapi/static/description/icon.png
  31. 2
      galicea_openid_connect/__init__.py
  32. 8
      galicea_openid_connect/__manifest__.py
  33. 35
      galicea_openid_connect/api.py
  34. 13
      galicea_openid_connect/controllers/main.py
  35. 1
      galicea_openid_connect/models/__init__.py
  36. 4
      galicea_openid_connect/models/client.py
  37. 28
      galicea_openid_connect/models/config_parameter.py
  38. 2
      galicea_openid_connect/random_tokens.py
  39. 8
      galicea_openid_connect/security/init.xml
  40. 5
      galicea_openid_connect/views/views.xml
  41. 30
      galicea_toolset/README.md
  42. 1
      galicea_toolset/__init__.py
  43. 20
      galicea_toolset/__manifest__.py
  44. 1
      galicea_toolset/static/src/js/.#one2many_flexible_widget.js
  45. 38
      galicea_toolset/static/src/js/client_actions.js
  46. 49
      galicea_toolset/static/src/js/iframe_widget.js
  47. 68
      galicea_toolset/static/src/js/one2many_flexible_widget.js
  48. 16
      galicea_toolset/utils.py
  49. 11
      galicea_toolset/views/data.xml

1
galicea_base/README.md

@ -0,0 +1 @@
Base menu for Odoo Galicea Ecosystem

2
galicea_base/__init__.py

@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-

23
galicea_base/__manifest__.py

@ -0,0 +1,23 @@
# -*- 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
}

6
galicea_base/views/base_menu.xml

@ -0,0 +1,6 @@
<?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>

6
galicea_environment_checkup/__init__.py

@ -1,7 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import models from . import models
from .environment_checkup.custom import custom_check
from .environment_checkup.core import CheckFail, CheckWarning, CheckSuccess
from . import controllers from . import controllers
from environment_checkup.custom import custom_check
from environment_checkup.core import CheckFail, CheckWarning, CheckSuccess

4
galicea_environment_checkup/__manifest__.py

@ -11,9 +11,9 @@
'website': "http://galicea.pl", 'website': "http://galicea.pl",
'category': 'Technical Settings', 'category': 'Technical Settings',
'version': '10.0.1.0',
'version': '12.0.1.0',
'depends': ['web'],
'depends': ['web','galicea_base',],
'data': [ 'data': [
'views/data.xml', 'views/data.xml',

4
galicea_environment_checkup/environment_checkup/__init__.py

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import core
from . import custom

2
galicea_environment_checkup/environment_checkup/custom.py

@ -2,7 +2,7 @@
import collections import collections
from core import Check
from .core import Check
custom_checks_per_module = collections.defaultdict(list) custom_checks_per_module = collections.defaultdict(list)

10
galicea_environment_checkup/environment_checkup/dependencies.py

@ -6,7 +6,7 @@ import cgi
from odoo.modules.module import load_information_from_description_file from odoo.modules.module import load_information_from_description_file
from odoo.tools import which from odoo.tools import which
from core import Check, CheckSuccess, CheckWarning, CheckFail
from .core import Check, CheckSuccess, CheckWarning, CheckFail
class DependencyCheck(Check): class DependencyCheck(Check):
dependency_type = None dependency_type = None
@ -36,8 +36,10 @@ class DependencyCheck(Check):
version_operator = version[:2] version_operator = version[:2]
version = version[2:] version = version[2:]
# Py3 : map -> list(map
# https://stackoverflow.com/questions/33717314/attributeerror-map-obejct-has-no-attribute-index-python-3
try: try:
parsed_version = map(int, version.split('.'))
parsed_version = list(map(int, version.split('.')))
except ValueError: except ValueError:
raise CheckFail( raise CheckFail(
'Invalid version expression', 'Invalid version expression',
@ -45,7 +47,7 @@ class DependencyCheck(Check):
Allowed expressions are <pre>=x.y.z</pre>, <pre>&gt;=x.y.z</pre>, <pre>^x.z.y</pre>, Allowed expressions are <pre>=x.y.z</pre>, <pre>&gt;=x.y.z</pre>, <pre>^x.z.y</pre>,
<pre>~x.y.z. Got <pre>{}</pre>""".format(cgi.escape(self.dependency['version'])) <pre>~x.y.z. Got <pre>{}</pre>""".format(cgi.escape(self.dependency['version']))
) )
parsed_installed_version = map(int, installed_version.split('.'))
parsed_installed_version = list(map(int, installed_version.split('.')))
parsed_version.extend(0 for _ in range(len(parsed_installed_version) - len(parsed_version))) 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))) parsed_installed_version.extend(0 for _ in range(len(parsed_version) - len(parsed_installed_version)))
@ -132,7 +134,7 @@ class ExternalDependencyCheck(DependencyCheck):
def _installed_version(self, env, name): def _installed_version(self, env, name):
try: try:
exe = which(name) exe = which(name)
out = subprocess.check_output([exe, '--version'])
out = str(subprocess.check_output([exe, '--version'])) # Py3 str()
match = re.search('[\d.]+', out) match = re.search('[\d.]+', out)
if not match: if not match:
raise CheckWarning( raise CheckWarning(

2
galicea_environment_checkup/environment_checkup/runtime.py

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import custom, dependencies
from . import custom, dependencies
def all_installed_checks(env): def all_installed_checks(env):
result = [] result = []

54
galicea_environment_checkup/static/src/js/environment_checkup.js

@ -1,12 +1,20 @@
odoo.define('galicea_environment_checkup', function (require) { odoo.define('galicea_environment_checkup', function (require) {
"use strict"; "use strict";
//var SystrayMenu = require('web.SystrayMenu');
//var Model = require('web.Model');
var AbstractAction = require('web.AbstractAction');
var core = require('web.core'); var core = require('web.core');
var form_common = require('web.form_common');
var Widget = require('web.Widget');
//var framework = require('web.framework');
var session = require('web.session'); var session = require('web.session');
//var Widget = require('web.Widget');
//////////////////
var QWeb = core.qweb; var QWeb = core.qweb;
var SystrayMenu = require('web.SystrayMenu');
//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 Model = require('web.Model');
var Users = new Model('res.users'); var Users = new Model('res.users');
@ -61,9 +69,11 @@ odoo.define('galicea_environment_checkup', function(require) {
}, },
}); });
SystrayMenu.Items.push(SystrayIcon);
*/
var Dashboard = Widget.extend({
/////////////////////////////
var Dashboard = AbstractAction.extend({
// v.10 var Dashboard = Widget.extend({
start: function(){ start: function(){
return this.load(this.all_dashboards); return this.load(this.all_dashboards);
}, },
@ -73,15 +83,17 @@ odoo.define('galicea_environment_checkup', function(require) {
var loading_done = new $.Deferred(); var loading_done = new $.Deferred();
session.rpc('/galicea_environment_checkup/data', {}) session.rpc('/galicea_environment_checkup/data', {})
.then(function (data) { .then(function (data) {
self.replaceElement(QWeb.render('GaliceaEnvironmentCheckupDashboard', {'data': data}));
self._replaceElement(QWeb.render('GaliceaEnvironmentCheckupDashboard', {'data': data})); // v.10: self.replaceElement
loading_done.resolve(); loading_done.resolve();
}); });
return loading_done; 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); core.action_registry.add('galicea_environment_checkup.dashboard', Dashboard);
////////////////////
/* v.10
var FormWidget = form_common.AbstractField.extend({ var FormWidget = form_common.AbstractField.extend({
init: function() { init: function() {
this._super.apply(this, arguments); this._super.apply(this, arguments);
@ -99,10 +111,36 @@ odoo.define('galicea_environment_checkup', function(require) {
}); });
core.form_widget_registry.add('environment_checks', FormWidget); 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 { return {
SystrayIcon: SystrayIcon,
//!! SystrayIcon: SystrayIcon,
Dashboard: Dashboard, Dashboard: Dashboard,
FormWidget: FormWidget FormWidget: FormWidget
}; };
}); });

108
galicea_environment_checkup/static/src/js/environment_checkup10.js

@ -0,0 +1,108 @@
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
};
});

6
galicea_environment_checkup/static/src/xml/templates.xml

@ -27,13 +27,13 @@
<div style="display: flex; background-color: white; padding: 10px; margin: 10px"> <div style="display: flex; background-color: white; padding: 10px; margin: 10px">
<div style="flex-grow: 0; flex-shrink: 0; width:50px; margin-right: 20px"> <div style="flex-grow: 0; flex-shrink: 0; width:50px; margin-right: 20px">
<t t-if="check.result == 'success'"> <t t-if="check.result == 'success'">
<i class="fa fa-check fa-4x" style="color: green" aria-hidden="true"></i>
<i class="fa fa-check fa-4x" style="color: green" ></i>
</t> </t>
<t t-if="check.result == 'warning'"> <t t-if="check.result == 'warning'">
<i class="fa fa-exclamation-triangle fa-4x" style="color: orange" aria-hidden="true"></i>
<i class="fa fa-exclamation-triangle fa-4x" style="color: orange" ></i>
</t> </t>
<t t-if="check.result == 'fail'"> <t t-if="check.result == 'fail'">
<i class="fa fa-exclamation-circle fa-4x" style="color: red" aria-hidden="true"></i>
<i class="fa fa-exclamation-circle fa-4x" style="color: red" ></i>
</t> </t>
</div> </div>
<div style="flex-grow: 1; flex-shrink: 1"> <div style="flex-grow: 1; flex-shrink: 1">

2
galicea_environment_checkup/views/views.xml

@ -5,7 +5,7 @@
<field name="tag">galicea_environment_checkup.dashboard</field> <field name="tag">galicea_environment_checkup.dashboard</field>
</record> </record>
<menuitem name="Environment check-up" id="dashboard_menu" <menuitem name="Environment check-up" id="dashboard_menu"
action="dashboard_action" parent="base.menu_administration" groups="base.group_erp_manager" />
action="dashboard_action" parent="galicea_base.galicea_admin_menu" groups="base.group_erp_manager" />
<record id="module_form" model="ir.ui.view"> <record id="module_form" model="ir.ui.view">
<field name="name">module_form.checks</field> <field name="name">module_form.checks</field>

4
galicea_git/__manifest__.py

@ -9,9 +9,9 @@
'website': "http://galicea.pl", 'website': "http://galicea.pl",
'category': 'Technical Settings', 'category': 'Technical Settings',
'version': '10.0.1.0',
'version': '12.0.0.1',
'depends': ['web', 'galicea_environment_checkup'],
'depends': ['web', 'galicea_environment_checkup','galicea_base'],
'external_dependencies': { 'external_dependencies': {
'bin': ['git'] 'bin': ['git']

8
galicea_git/controllers/main.py

@ -65,14 +65,14 @@ class Main(http.Controller):
shell=True shell=True
) )
stdout, stderr = git.communicate(http_input_stream(request).read()) stdout, stderr = git.communicate(http_input_stream(request).read())
headers_str, body = stdout.split("\r\n\r\n", 2)
headers_str, body = stdout.split(b"\r\n\r\n", 2)
http_status_code = 200 http_status_code = 200
headers = [] headers = []
for header in headers_str.split("\r\n"):
name, value = header.split(': ', 2)
for header in headers_str.split(b"\r\n"):
name, value = header.split(b': ', 2)
if name == 'Status': if name == 'Status':
http_code = int(value.split(' ')[0])
http_code = int(value.split(b' ')[0])
else: else:
headers.append((name, value)) headers.append((name, value))

3
galicea_git/data/config.xml

@ -1,9 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<data noupdate="1"> <data noupdate="1">
<record id="config_git_backend_path" model="ir.config_parameter"> <record id="config_git_backend_path" model="ir.config_parameter">
<field name="key">galicea_git.git_http_backend</field> <field name="key">galicea_git.git_http_backend</field>
<field name="value">/usr/lib/git-core/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'))]" /> <field name="group_ids" eval="[(4, ref('galicea_git.group_admin'))]" />
</record> </record>
</data> </data>
</odoo> </odoo>

7
galicea_git/models/repository.py

@ -5,6 +5,11 @@ import random
import shutil import shutil
import string import string
import subprocess import subprocess
try:
import git
except ImportError:
pass
from odoo import models, fields, api, http from odoo import models, fields, api, http
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
@ -56,7 +61,7 @@ class Repository(models.Model):
@api.constrains('system_name') @api.constrains('system_name')
def _validate_system_name(self): def _validate_system_name(self):
allowed_characters = string.ascii_lowercase + string.digits + '-'
allowed_characters = string.ascii_lowercase + string.digits + '-_'
if not all(c in allowed_characters for c in self.system_name): if not all(c in allowed_characters for c in self.system_name):
raise ValidationError( raise ValidationError(
'Only lowercase, digits and hyphens (-) are allowed in directory name' 'Only lowercase, digits and hyphens (-) are allowed in directory name'

71
galicea_git/views/views.org.xml

@ -0,0 +1,71 @@
<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>

35
galicea_git/views/views.xml

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<data>
<record id="repository_view_form" model="ir.ui.view"> <record id="repository_view_form" model="ir.ui.view">
<field name="model">galicea_git.repository</field> <field name="model">galicea_git.repository</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
@ -33,34 +36,8 @@
name="Git repositories" name="Git repositories"
res_model="galicea_git.repository" /> 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"
view_mode="form" target="inline" />
<menuitem name="Repositories" id="repo_menu" parent="galicea_base.galicea_admin_menu"
action="repository_action" sequence="1" />
<menuitem name="Git hosting" id="root_menu" sequence="20" />
<menuitem name="Repositories" id="repo_menu" parent="galicea_git.root_menu" action="repository_action" sequence="1" />
<menuitem name="Settings" id="settings_menu" parent="galicea_git.root_menu" action="config_settings_action" sequence="99"
groups="galicea_git.group_admin" />
</data>
</odoo> </odoo>

5
galicea_openapi/__init__.py

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
#from . import models
from . import controllers

33
galicea_openapi/__manifest__.py

@ -0,0 +1,33 @@
# -*- 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,
}

4
galicea_openapi/controllers/__init__.py

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import api

56
galicea_openapi/controllers/api.py

@ -0,0 +1,56 @@
# -*- 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

22
galicea_openapi/doc/helloworld.py

@ -0,0 +1,22 @@
# 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)

41
galicea_openapi/doc/test1.py

@ -0,0 +1,41 @@
# 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)

3
galicea_openapi/models/__init__.py

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-

52
galicea_openapi/openapi.py

@ -0,0 +1,52 @@
# -*- 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
#

2
galicea_openapi/security/ir.model.access.csv

@ -0,0 +1,2 @@
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

BIN
galicea_openapi/static/description/icon.png

After

Width: 128  |  Height: 128  |  Size: 10 KiB

2
galicea_openid_connect/__init__.py

@ -3,3 +3,5 @@
from . import controllers from . import controllers
from . import models from . import models
from . import system_checks from . import system_checks
from . import api

8
galicea_openid_connect/__manifest__.py

@ -9,9 +9,9 @@
'website': "http://galicea.pl", 'website': "http://galicea.pl",
'category': 'Technical Settings', 'category': 'Technical Settings',
'version': '10.0.1.3',
'version': '12.0.0.0',
'depends': ['web', 'galicea_environment_checkup'],
'depends': ['web', 'galicea_environment_checkup', 'galicea_base' ],
'external_dependencies': { 'external_dependencies': {
'python': ['jwcrypto', 'cryptography'] 'python': ['jwcrypto', 'cryptography']
@ -20,8 +20,8 @@
'data': [ 'data': [
'security/security.xml', 'security/security.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'security/init.yml',
# 'security/init.yml',
'security/init.xml',
'views/views.xml', 'views/views.xml',
'views/templates.xml' 'views/templates.xml'
], ],

35
galicea_openid_connect/api.py

@ -16,13 +16,7 @@ class ApiException(Exception):
super(Exception, self).__init__(message) super(Exception, self).__init__(message)
self.code = code if code else self.INVALID_REQUEST self.code = code if code else self.INVALID_REQUEST
def to_json(self):
return {
'error': self.code,
'error_message': self.message
}
def resource(path, method, auth='user', clients=None):
def resource(path, method, auth='user'):
assert auth in ['user', 'client'] assert auth in ['user', 'client']
def endpoint_decorator(func): def endpoint_decorator(func):
@ -33,7 +27,6 @@ def resource(path, method, auth='user', clients=None):
'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, X-Debug-Mode, Authorization', 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, X-Debug-Mode, Authorization',
'Access-Control-Max-Age': 60 * 60 * 24, 'Access-Control-Max-Age': 60 * 60 * 24,
'Access-Control-Allow-Methods': 'OPTIONS, HEAD, GET, POST, PUT, DELETE'
} }
if req.httprequest.method == 'OPTIONS': if req.httprequest.method == 'OPTIONS':
return http.Response( return http.Response(
@ -75,10 +68,6 @@ def resource(path, method, auth='user', clients=None):
) )
req.uid = token.client_id.system_user_id.id req.uid = token.client_id.system_user_id.id
if clients:
if token.client_id.id not in map(lambda c: req.env.ref(c).id, clients):
raise ApiException('Access denied', 'restricted_app')
ctx = req.context.copy() ctx = req.context.copy()
ctx.update({'client_id': token.client_id.id}) ctx.update({'client_id': token.client_id.id})
req.context = ctx req.context = ctx
@ -89,17 +78,23 @@ def resource(path, method, auth='user', clients=None):
headers=cors_headers, headers=cors_headers,
status=200 status=200
) )
except Exception as e:
status = 400
if not isinstance(e, ApiException):
_logger.exception('Unexpected exception while processing API request')
e = ApiException('Unexpected server error', 'server_error')
status = 500
except ApiException as e:
error_message = "error: {0}".format(e)
return werkzeug.Response( return werkzeug.Response(
response=json.dumps(e.to_json()),
status=status,
response=json.dumps({'error': e.code, 'error_message': error_message}),
status=400,
headers=cors_headers headers=cors_headers
) )
except:
_logger.exception('Unexpected exception while processing API request')
return werkzeug.Response(
response=json.dumps({
'error': 'server_error',
'error_message': 'Unexpected server error',
}),
headers=cors_headers,
status=500
)
return func_wrapper return func_wrapper
return endpoint_decorator return endpoint_decorator

13
galicea_openid_connect/controllers/main.py

@ -47,7 +47,6 @@ class OAuthException(Exception):
UNSUPPORTED_RESPONSE_TYPE = 'unsupported_response_type' UNSUPPORTED_RESPONSE_TYPE = 'unsupported_response_type'
INVALID_GRANT = 'invalid_grant' INVALID_GRANT = 'invalid_grant'
UNSUPPORTED_GRANT_TYPE = 'unsupported_grant_type' UNSUPPORTED_GRANT_TYPE = 'unsupported_grant_type'
RESTRICTED_APP = 'restricted_app'
def __init__(self, message, type): def __init__(self, message, type):
super(Exception, self).__init__(message) super(Exception, self).__init__(message)
@ -104,15 +103,6 @@ class Main(http.Controller):
OAuthException.INVALID_CLIENT, OAuthException.INVALID_CLIENT,
) )
def __validate_user(self, client, user):
if not client.user_group_id:
return
if client.user_group_id not in user.groups_id:
raise OAuthException(
'User is not allowed to use this client',
OAuthException.RESTRICTED_APP
)
@http.route('/.well-known/openid-configuration', auth='public', type='http') @http.route('/.well-known/openid-configuration', auth='public', type='http')
def metadata(self, req, **query): def metadata(self, req, **query):
base_url = http.request.httprequest.host_url base_url = http.request.httprequest.host_url
@ -216,7 +206,6 @@ class Main(http.Controller):
} }
return self.__redirect('/web/login', params, 'query') return self.__redirect('/web/login', params, 'query')
self.__validate_user(client, user)
response_types = response_type.split() response_types = response_type.split()
extra_claims = { extra_claims = {
@ -366,7 +355,7 @@ class Main(http.Controller):
'Invalid username or password', 'Invalid username or password',
OAuthException.INVALID_REQUEST OAuthException.INVALID_REQUEST
) )
self.__validate_user(client, req.env['res.users'].sudo().browse(user_id))
scopes = query['scope'].split(' ') if query.get('scope') else [] scopes = query['scope'].split(' ') if query.get('scope') else []
# Retrieve/generate access token. We currently only store one per user/client # Retrieve/generate access token. We currently only store one per user/client
token = req.env['galicea_openid_connect.access_token'].sudo().retrieve_or_create( token = req.env['galicea_openid_connect.access_token'].sudo().retrieve_or_create(

1
galicea_openid_connect/models/__init__.py

@ -2,3 +2,4 @@
from . import client from . import client
from . import access_token from . import access_token
from . import config_parameter

4
galicea_openid_connect/models/client.py

@ -34,10 +34,6 @@ class Client(models.Model):
string='Allow OAuth2 password grant', string='Allow OAuth2 password grant',
default=False, default=False,
) )
user_group_id = fields.Many2one(
'res.groups',
'Restrict the client to a group'
)
@api.model @api.model
def __system_user_name(self, client_name): def __system_user_name(self, client_name):

28
galicea_openid_connect/models/config_parameter.py

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api
from .. import random_tokens
try:
from jwcrypto import jwk
except ImportError:
pass
class ConfigParameter(models.Model):
_inherit = 'ir.config_parameter'
@api.model
def openid_init_keys(self):
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()
}
for key, gen in iter(keys.items()):
if not self.search([('key', '=', key)]):
self.create({
'key': key,
'value': gen(),
'group_ids': [(4, self.env.ref('base.group_erp_manager').id)]
})

2
galicea_openid_connect/random_tokens.py

@ -3,7 +3,7 @@
from random import SystemRandom from random import SystemRandom
def random_token(length, byte_filter): def random_token(length, byte_filter):
allowed_bytes = ''.join(c for c in map(chr, range(256)) if byte_filter(c))
allowed_bytes = ''.join(c for c in map(chr, range(128)) if byte_filter(c))
random = SystemRandom() random = SystemRandom()
return ''.join([random.choice(allowed_bytes) for _ in range(length)]) return ''.join([random.choice(allowed_bytes) for _ in range(length)])

8
galicea_openid_connect/security/init.xml

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<function model="ir.config_parameter"
name="openid_init_keys"
/>
</data>
</odoo>

5
galicea_openid_connect/views/views.xml

@ -28,7 +28,6 @@
<button class="oe_read_only" string="Show" type="action" name="%(client_action_secret)d" /> <button class="oe_read_only" string="Show" type="action" name="%(client_action_secret)d" />
<field name="auth_redirect_uri" /> <field name="auth_redirect_uri" />
<field name="allow_password_grant" /> <field name="allow_password_grant" />
<field name="user_group_id" />
</group> </group>
</form> </form>
</field> </field>
@ -61,7 +60,7 @@
name="OpenID Clients" name="OpenID Clients"
res_model="galicea_openid_connect.client" /> res_model="galicea_openid_connect.client" />
<menuitem name="OpenID Connect Provider" id="root_menu" sequence="19" />
<menuitem name="Clients" id="client_menu" parent="galicea_openid_connect.root_menu" action="client_action" />
<menuitem name="OpenID Connect Provider" id="client_menu"
parent="galicea_base.galicea_admin_menu" action="client_action" />
</data> </data>
</odoo> </odoo>

30
galicea_toolset/README.md

@ -0,0 +1,30 @@
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
galicea_toolset/__init__.py

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

20
galicea_toolset/__manifest__.py

@ -0,0 +1,20 @@
# -*- 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
galicea_toolset/static/src/js/.#one2many_flexible_widget.js

@ -0,0 +1 @@
jurek@jurek.15022

38
galicea_toolset/static/src/js/client_actions.js

@ -0,0 +1,38 @@
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,
};
});

49
galicea_toolset/static/src/js/iframe_widget.js

@ -0,0 +1,49 @@
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,
};
});

68
galicea_toolset/static/src/js/one2many_flexible_widget.js

@ -0,0 +1,68 @@
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,
};
});

16
galicea_toolset/utils.py

@ -0,0 +1,16 @@
# -*- 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') + '/'

11
galicea_toolset/views/data.xml

@ -0,0 +1,11 @@
<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>
Loading…
Cancel
Save