Merge branch 'flectra-app-store' into 'master'
[IMP] improvement on app store. See merge request flectra-hq/flectra!162
This commit is contained in:
commit
c3cd4c4867
@ -1,6 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
||||||
import tarfile
|
import tarfile
|
||||||
|
import uuid
|
||||||
|
|
||||||
import babel.messages.pofile
|
import babel.messages.pofile
|
||||||
import base64
|
import base64
|
||||||
@ -570,7 +571,7 @@ class Home(http.Controller):
|
|||||||
|
|
||||||
@http.route(['/web/app_action'], type='json', auth="user")
|
@http.route(['/web/app_action'], type='json', auth="user")
|
||||||
def app_action(self, action='', module_name='', **kwargs):
|
def app_action(self, action='', module_name='', **kwargs):
|
||||||
if request.env.user.has_group('base.group_system'):
|
if request.env.user.has_group('base.group_system') and config.get('app_store') == 'install':
|
||||||
if module_name and action:
|
if module_name and action:
|
||||||
module = request.env['ir.module.module'].search([('state', '=', 'installed'), ('name', '=', module_name)], limit=1)
|
module = request.env['ir.module.module'].search([('state', '=', 'installed'), ('name', '=', module_name)], limit=1)
|
||||||
if module:
|
if module:
|
||||||
@ -581,7 +582,7 @@ class Home(http.Controller):
|
|||||||
|
|
||||||
@http.route(['/web/get_modules'], type='json', auth="user")
|
@http.route(['/web/get_modules'], type='json', auth="user")
|
||||||
def get_modules(self, **kwargs):
|
def get_modules(self, **kwargs):
|
||||||
if request.env.user.has_group('base.group_system'):
|
if request.env.user.has_group('base.group_system') and config.get('app_store') in ['install', 'download']:
|
||||||
try:
|
try:
|
||||||
modules = request.env['ir.module.module'].search_read([('state', '=', 'installed')], fields=['name'])
|
modules = request.env['ir.module.module'].search_read([('state', '=', 'installed')], fields=['name'])
|
||||||
p = requests.post(server_url + '/flectrahq/get_modules', data=kwargs)
|
p = requests.post(server_url + '/flectrahq/get_modules', data=kwargs)
|
||||||
@ -595,11 +596,11 @@ class Home(http.Controller):
|
|||||||
return False
|
return False
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@http.route(['/web/module_download/<int:id>'], type='http', auth="user", methods=['GET', 'POST'])
|
@http.route(['/web/module_download/<string:id>'], type='http', auth="user", methods=['GET', 'POST'])
|
||||||
def app_download(self, id=None):
|
def app_download(self, id=None, **kwargs):
|
||||||
if request.env.user.has_group('base.group_system'):
|
if request.env.user.has_group('base.group_system') and config.get('app_store') in ['install', 'download']:
|
||||||
dbuuid = request.env['ir.config_parameter'].get_param('database.uuid')
|
dbuuid = request.env['ir.config_parameter'].get_param('database.uuid')
|
||||||
p = requests.get(server_url + '/flectrahq/get_module_zip/' + str(id) + '/1', params={'dbuuid': dbuuid})
|
p = requests.get(server_url + '/flectrahq/get_module_zip/' + str(id), params={'dbuuid': dbuuid})
|
||||||
try:
|
try:
|
||||||
data = json.loads(p.content.decode('utf-8'))
|
data = json.loads(p.content.decode('utf-8'))
|
||||||
if data.get('error', False):
|
if data.get('error', False):
|
||||||
@ -618,17 +619,12 @@ class Home(http.Controller):
|
|||||||
return request.not_found()
|
return request.not_found()
|
||||||
return request.not_found()
|
return request.not_found()
|
||||||
|
|
||||||
@http.route(['/web/app_download_install/<int:id>'], type='json', auth="user")
|
@http.route(['/web/app_download_install'], type='json', auth="user")
|
||||||
def app_download_install(self, id=None):
|
def app_download_install(self, checksum=None, module_name=None, id=None, **kwargs):
|
||||||
if request.env.user.has_group('base.group_system'):
|
if request.env.user.has_group('base.group_system') and config.get('app_store') == 'install':
|
||||||
IrModule = request.env['ir.module.module']
|
IrModule = request.env['ir.module.module']
|
||||||
try:
|
try:
|
||||||
res_get_details = requests.get(server_url + '/flectrahq/get_module_zip/' + str(id) + '/0')
|
res_download = requests.get(server_url + '/flectrahq/get_module_zip/' + str(id))
|
||||||
module_file_details = json.loads(res_get_details.content.decode('utf-8'))
|
|
||||||
except:
|
|
||||||
return {"error": "Internal Server Error"}
|
|
||||||
finally:
|
|
||||||
res_download = requests.get(server_url + '/flectrahq/get_module_zip/' + str(id) + '/1')
|
|
||||||
downloaded_file_checksum = hashlib.sha1(res_download.content or b'').hexdigest()
|
downloaded_file_checksum = hashlib.sha1(res_download.content or b'').hexdigest()
|
||||||
if res_download.status_code == 200:
|
if res_download.status_code == 200:
|
||||||
try:
|
try:
|
||||||
@ -637,9 +633,8 @@ class Home(http.Controller):
|
|||||||
return data
|
return data
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
if checksum == downloaded_file_checksum:
|
||||||
if module_file_details['checksum'] == downloaded_file_checksum:
|
path = os.path.join(tmp_dir_path, uuid.uuid4().hex)
|
||||||
path = os.path.join(tmp_dir_path, module_file_details['name'])
|
|
||||||
try:
|
try:
|
||||||
with open(path, 'wb') as f:
|
with open(path, 'wb') as f:
|
||||||
f.write(res_download.content)
|
f.write(res_download.content)
|
||||||
@ -650,14 +645,15 @@ class Home(http.Controller):
|
|||||||
finally:
|
finally:
|
||||||
IrModule.update_list()
|
IrModule.update_list()
|
||||||
root.load_addons()
|
root.load_addons()
|
||||||
modules = IrModule.search([('name', '=', module_file_details['module_name'])], limit=1)
|
if module_name:
|
||||||
|
modules = IrModule.search([('name', '=', module_name)], limit=1)
|
||||||
modules.button_immediate_install()
|
modules.button_immediate_install()
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
return {"success": "Module is successfully installed."}
|
return {"success": "Module is successfully installed."}
|
||||||
else:
|
else:
|
||||||
return {"error": "File Crash."}
|
return {"error": "File crashed when downloading."}
|
||||||
|
except:
|
||||||
return {"error": "Internal Server Error."}
|
return {"error": "Internal Server Error"}
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,27 +99,20 @@ var Apps = Widget.extend({
|
|||||||
},
|
},
|
||||||
_openDialogAfterAction: function (data) {
|
_openDialogAfterAction: function (data) {
|
||||||
if (!_.isEmpty(data)) {
|
if (!_.isEmpty(data)) {
|
||||||
var buttons = [];
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
buttons.push({
|
|
||||||
text: _t("Refresh"),
|
|
||||||
classes: 'btn-success',
|
|
||||||
click: function (e) {
|
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
},
|
return;
|
||||||
close: true
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
buttons.push({
|
var buttons = [{
|
||||||
text: _t("Cancel"),
|
text: _t("OK"),
|
||||||
classes: 'btn-warning',
|
classes: 'btn-success',
|
||||||
close: true,
|
close: true,
|
||||||
});
|
}];
|
||||||
var dialog = new Dialog(this, {
|
var dialog = new Dialog(this, {
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
buttons: buttons,
|
buttons: buttons,
|
||||||
$content: $("<h4>" + (data.error || data.success) + "</h4>"),
|
$content: $("<h4>" + data.error + "</h4>"),
|
||||||
title: _t(data.error ? "Error" : "Message"),
|
title: _t("Error"),
|
||||||
});
|
});
|
||||||
dialog.open();
|
dialog.open();
|
||||||
}
|
}
|
||||||
@ -152,8 +145,14 @@ var Apps = Widget.extend({
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var self = this;
|
var self = this;
|
||||||
var id = $(e.target).data("module-id");
|
var id = $(e.target).data("module-id");
|
||||||
|
var data = _.findWhere(this.all_app, {id: id});
|
||||||
self._rpc({
|
self._rpc({
|
||||||
route: '/web/app_download_install/' + id,
|
route: '/web/app_download_install',
|
||||||
|
params: {
|
||||||
|
id: data['md5_val'],
|
||||||
|
checksum: data['checksum'],
|
||||||
|
module_name: data['technical_name']
|
||||||
|
}
|
||||||
}).then(function (data) {
|
}).then(function (data) {
|
||||||
self._openDialogAfterAction(data);
|
self._openDialogAfterAction(data);
|
||||||
});
|
});
|
||||||
@ -172,10 +171,11 @@ var Apps = Widget.extend({
|
|||||||
params: {
|
params: {
|
||||||
offset: this.context.categ[this.active_categ]['offset'],
|
offset: this.context.categ[this.active_categ]['offset'],
|
||||||
categ: this.active_categ,
|
categ: this.active_categ,
|
||||||
search: this.context.categ[self.active_categ]['search']
|
search: this.context.categ[this.active_categ]['search']
|
||||||
}
|
}
|
||||||
}).done(function (data) {
|
}).done(function (data) {
|
||||||
if (data) {
|
if (data) {
|
||||||
|
self.all_app = self.all_app.concat(data.modules[self.active_categ]);
|
||||||
self.$el.find('#' + self.active_categ + " .module-kanban:last")
|
self.$el.find('#' + self.active_categ + " .module-kanban:last")
|
||||||
.after(QWeb.render('AppStore.ModuleBoxContainer', {
|
.after(QWeb.render('AppStore.ModuleBoxContainer', {
|
||||||
modules: data.modules[self.active_categ],
|
modules: data.modules[self.active_categ],
|
||||||
@ -183,10 +183,15 @@ var Apps = Widget.extend({
|
|||||||
mode: self.mode,
|
mode: self.mode,
|
||||||
store_url: data.store_url
|
store_url: data.store_url
|
||||||
}));
|
}));
|
||||||
if (!_.isEmpty(data.modules[self.active_categ])) {
|
if (!_.isEmpty(data.modules[self.active_categ]) && data.modules[self.active_categ].length == data.limit) {
|
||||||
self.$el.find('#' + self.active_categ + " .load-more").show();
|
self.$el.find('#' + self.active_categ + " .load-more").show();
|
||||||
} else {
|
} else {
|
||||||
self.$el.find('#' + self.active_categ + " .load-more").hide();
|
var $rec = self.$el.find('#' + self.active_categ + " .module-kanban ");
|
||||||
|
var $load_more = self.$el.find('#' + self.active_categ + " .load-more");
|
||||||
|
$load_more.hide().next('h3').remove();
|
||||||
|
if (!$rec.length) {
|
||||||
|
$load_more.after('<h3>No such module(s) found.</h3>');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.$el.html(QWeb.render('AppStore.TryError', {}));
|
self.$el.html(QWeb.render('AppStore.TryError', {}));
|
||||||
@ -227,18 +232,25 @@ var Apps = Widget.extend({
|
|||||||
}
|
}
|
||||||
}).done(function (data) {
|
}).done(function (data) {
|
||||||
if (data) {
|
if (data) {
|
||||||
|
self.all_app = self.all_app.concat(data.modules[self.active_categ]);
|
||||||
self.$el.find('#' + self.active_categ).find('.module-kanban').remove();
|
self.$el.find('#' + self.active_categ).find('.module-kanban').remove();
|
||||||
self.context.categ[self.active_categ]['search'] = search;
|
self.context.categ[self.active_categ]['search'] = search;
|
||||||
|
self.context.categ[self.active_categ]['offset'] = 0;
|
||||||
$(QWeb.render('AppStore.ModuleBoxContainer', {
|
$(QWeb.render('AppStore.ModuleBoxContainer', {
|
||||||
modules: data.modules[self.active_categ],
|
modules: data.modules[self.active_categ],
|
||||||
installed_modules: data.installed_modules,
|
installed_modules: data.installed_modules,
|
||||||
mode: self.mode,
|
mode: self.mode,
|
||||||
store_url: data.store_url
|
store_url: data.store_url
|
||||||
})).prependTo(self.$el.find('#' + self.active_categ + " .o_kanban_view"));
|
})).prependTo(self.$el.find('#' + self.active_categ + " .o_kanban_view"));
|
||||||
if (!_.isEmpty(data.modules[self.active_categ])) {
|
if (!_.isEmpty(data.modules[self.active_categ]) && data.modules[self.active_categ].length == data.limit) {
|
||||||
self.$el.find('#' + self.active_categ + " .load-more").show().next('h3').remove();
|
self.$el.find('#' + self.active_categ + " .load-more").show().next('h3').remove();
|
||||||
} else {
|
} else {
|
||||||
self.$el.find('#' + self.active_categ + " .load-more").hide().after('<h3>No such module(s) found.</h3>');
|
var $rec = self.$el.find('#' + self.active_categ + " .module-kanban ");
|
||||||
|
var $load_more = self.$el.find('#' + self.active_categ + " .load-more");
|
||||||
|
$load_more.hide().next('h3').remove();
|
||||||
|
if (!$rec.length) {
|
||||||
|
$load_more.after('<h3>No such module(s) found.</h3>');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.$el.html(QWeb.render('AppStore.TryError', {}));
|
self.$el.html(QWeb.render('AppStore.TryError', {}));
|
||||||
|
@ -32,12 +32,15 @@
|
|||||||
}
|
}
|
||||||
li {
|
li {
|
||||||
float: none;
|
float: none;
|
||||||
> a:hover, > a:focus {
|
> a {
|
||||||
|
white-space: nowrap;
|
||||||
|
&:hover, &:focus {
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
background-color: mix(@brand-primary, #ffffff, 50%);
|
background-color: mix(@brand-primary, #ffffff, 50%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@media (max-width: @screen-sm-max) {
|
@media (max-width: @screen-sm-max) {
|
||||||
border-top: none;
|
border-top: none;
|
||||||
}
|
}
|
||||||
@ -70,13 +73,13 @@
|
|||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
.oe_module_desc {
|
.oe_module_desc {
|
||||||
|
min-height: 130px;
|
||||||
.oe_module_action {
|
.oe_module_action {
|
||||||
.o_module_tech_name {
|
|
||||||
display: inline-block;
|
|
||||||
width: 140px;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden !important;
|
overflow: hidden !important;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
.o_module_tech_name {
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1495,7 +1495,7 @@
|
|||||||
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
|
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
|
||||||
<t t-set="is_install" t-value="installed_modules.includes(m.technical_name)"/>
|
<t t-set="is_install" t-value="installed_modules.includes(m.technical_name)"/>
|
||||||
<li><a t-if="is_install and mode == 'install'" app-action="uninstall" t-att-data-module-id="m.id" href="#" class=" oe_kanban_action oe_kanban_action_a">Uninstall</a></li>
|
<li><a t-if="is_install and mode == 'install'" app-action="uninstall" t-att-data-module-id="m.id" href="#" class=" oe_kanban_action oe_kanban_action_a">Uninstall</a></li>
|
||||||
<li><a app-action="download" t-att-data-module-id="m.id" t-att-href="m.price ? 'javascript:void(0);' : '/web/module_download/' + m.id" class=" oe_kanban_action oe_kanban_action_a">Download</a></li>
|
<li><a app-action="download" t-att-data-module-id="m.id" t-att-href="m.price ? 'javascript:void(0);' : '/web/module_download/' + m.md5_val" class=" oe_kanban_action oe_kanban_action_a">Download</a></li>
|
||||||
<li><a app-action="view-info" t-att-data-module-id="m.id" href="#" class="oe_kanban_action oe_kanban_action_a">View Info</a></li>
|
<li><a app-action="view-info" t-att-data-module-id="m.id" href="#" class="oe_kanban_action oe_kanban_action_a">View Info</a></li>
|
||||||
<li><a t-attf-href="{{ store_url }}/apps/{{ m.version }}/{{ m.technical_name }}" target="_blank" class=" oe_kanban_action oe_kanban_action_a">View More on Store</a></li>
|
<li><a t-attf-href="{{ store_url }}/apps/{{ m.version }}/{{ m.technical_name }}" target="_blank" class=" oe_kanban_action oe_kanban_action_a">View More on Store</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -1507,9 +1507,13 @@
|
|||||||
<span><t t-esc="m.description or ''"/></span>
|
<span><t t-esc="m.description or ''"/></span>
|
||||||
</p>
|
</p>
|
||||||
<div class="oe_module_action">
|
<div class="oe_module_action">
|
||||||
<span class="pull-left"><t t-esc="m.price ? m.price + ' ' + m.currency[1] : 'Free'"/></span><br/>
|
<span t-if="m.price">
|
||||||
<code class="pull-left o_module_tech_name"><small><span><t t-esc="m.technical_name"/></span></small></code>
|
<t t-esc="m.currency[2] == 'after' ? m.price + ' ' + m.currency[1] : m.currency[1] + ' ' + m.price"/>
|
||||||
<div class="text-right">
|
</span>
|
||||||
|
<span t-else="m.price">Free</span>
|
||||||
|
<br/>
|
||||||
|
<code class="o_module_tech_name" t-att-title="m.technical_name"><small><span><t t-esc="m.technical_name"/></span></small></code>
|
||||||
|
<div class="text-right mt8">
|
||||||
<t t-if="is_install">
|
<t t-if="is_install">
|
||||||
<span>Installed</span>
|
<span>Installed</span>
|
||||||
</t>
|
</t>
|
||||||
@ -1521,7 +1525,7 @@
|
|||||||
</t>
|
</t>
|
||||||
<t t-else="">
|
<t t-else="">
|
||||||
<button t-if="mode == 'install'" app-action="install" t-att-data-module-id="m.id" class="btn btn-primary btn-sm oe_kanban_action oe_kanban_action_button">Install</button>
|
<button t-if="mode == 'install'" app-action="install" t-att-data-module-id="m.id" class="btn btn-primary btn-sm oe_kanban_action oe_kanban_action_button">Install</button>
|
||||||
<a t-if="mode == 'download'" app-action="download" t-att-href="m.price ? 'javascript:void(0);' : '/web/module_download/' + m.id " t-att-data-module-id="m.id" class="btn btn-primary btn-sm oe_kanban_action oe_kanban_action_button">
|
<a t-if="mode == 'download'" app-action="download" t-att-href="m.price ? 'javascript:void(0);' : '/web/module_download/' + m.md5_val " t-att-data-module-id="m.id" class="btn btn-primary btn-sm oe_kanban_action oe_kanban_action_button">
|
||||||
<span><i class="fa fa-download"/></span>
|
<span><i class="fa fa-download"/></span>
|
||||||
</a>
|
</a>
|
||||||
</t>
|
</t>
|
||||||
@ -1607,7 +1611,11 @@
|
|||||||
<span><t t-esc="m.description or ''"/></span>
|
<span><t t-esc="m.description or ''"/></span>
|
||||||
</p>
|
</p>
|
||||||
<div class="oe_module_action">
|
<div class="oe_module_action">
|
||||||
<span><t t-esc="m.price ? m.price + ' ' + m.currency[1] : 'Free'"/></span><br/>
|
<span t-if="m.price">
|
||||||
|
<t t-esc="m.currency[2] == 'after' ? m.price + ' ' + m.currency[1] : m.currency[1] + ' ' + m.price"/>
|
||||||
|
</span>
|
||||||
|
<span t-else="m.price">Free</span>
|
||||||
|
<br/>
|
||||||
<code><small><span><t t-esc="m.technical_name"/></span></small></code>
|
<code><small><span><t t-esc="m.technical_name"/></span></small></code>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -636,9 +636,11 @@ class configmanager(object):
|
|||||||
except OSError:
|
except OSError:
|
||||||
logging.getLogger(__name__).debug('Failed to create addons data dir %s', d)
|
logging.getLogger(__name__).debug('Failed to create addons data dir %s', d)
|
||||||
try:
|
try:
|
||||||
if self.get('db_name') and not os.listdir(os.path.join(d)):
|
try:
|
||||||
|
from flectra.http import request, root
|
||||||
|
if request.session.db and not os.listdir(os.path.join(d)):
|
||||||
from flectra.sql_db import db_connect
|
from flectra.sql_db import db_connect
|
||||||
with closing(db_connect(self.get('db_name')).cursor()) as cr:
|
with closing(db_connect(request.session.db).cursor()) as cr:
|
||||||
if flectra.tools.table_exists(cr, 'ir_module_module'):
|
if flectra.tools.table_exists(cr, 'ir_module_module'):
|
||||||
cr.execute("SELECT latest_version FROM ir_module_module WHERE name=%s", ('base',))
|
cr.execute("SELECT latest_version FROM ir_module_module WHERE name=%s", ('base',))
|
||||||
base_version = cr.fetchone()
|
base_version = cr.fetchone()
|
||||||
@ -648,6 +650,9 @@ class configmanager(object):
|
|||||||
s = os.path.join(add_dir, last_version)
|
s = os.path.join(add_dir, last_version)
|
||||||
if float(last_version) < float(release.series) and os.listdir(os.path.join(s)):
|
if float(last_version) < float(release.series) and os.listdir(os.path.join(s)):
|
||||||
self.copytree(s, d)
|
self.copytree(s, d)
|
||||||
|
root.load_addons()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
if self.get('app_store') == 'install':
|
if self.get('app_store') == 'install':
|
||||||
if not os.access(d, os.W_OK):
|
if not os.access(d, os.W_OK):
|
||||||
|
Loading…
Reference in New Issue
Block a user