2009-10-20 10:52:23 +00:00
# -*- coding: utf-8 -*-
2006-12-07 13:41:40 +00:00
##############################################################################
2009-11-20 11:39:28 +00:00
#
2009-10-14 12:32:15 +00:00
# OpenERP, Open Source Management Solution
2014-10-21 10:48:19 +00:00
# Copyright (C) 2004-2014 OpenERP S.A. (<http://openerp.com>).
2008-06-16 11:00:21 +00:00
#
2008-11-03 18:27:16 +00:00
# This program is free software: you can redistribute it and/or modify
2009-10-14 12:32:15 +00:00
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
2006-12-07 13:41:40 +00:00
#
2008-11-03 18:27:16 +00:00
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2009-10-14 12:32:15 +00:00
# GNU Affero General Public License for more details.
2006-12-07 13:41:40 +00:00
#
2009-10-14 12:32:15 +00:00
# You should have received a copy of the GNU Affero General Public License
2009-11-20 11:39:28 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2006-12-07 13:41:40 +00:00
#
##############################################################################
2012-12-17 14:30:29 +00:00
from docutils import nodes
2012-08-23 08:35:05 +00:00
from docutils . core import publish_string
2012-10-25 13:01:11 +00:00
from docutils . transforms import Transform , writer_aux
from docutils . writers . html4css1 import Writer
2015-07-03 09:55:58 +00:00
import importlib
2010-06-16 10:26:10 +00:00
import logging
2013-09-19 11:50:14 +00:00
from operator import attrgetter
2012-08-22 17:44:13 +00:00
import os
2010-09-29 06:54:41 +00:00
import re
2012-08-22 17:44:13 +00:00
import shutil
import tempfile
2010-09-29 06:54:41 +00:00
import urllib
2012-09-11 10:30:02 +00:00
import urllib2
2013-02-18 17:55:59 +00:00
import urlparse
2012-08-22 17:44:13 +00:00
import zipfile
2008-01-15 14:01:08 +00:00
import zipimport
2013-05-30 13:51:47 +00:00
import lxml . html
2007-07-30 13:35:27 +00:00
2012-08-22 17:44:13 +00:00
try :
from cStringIO import StringIO
except ImportError :
from StringIO import StringIO # NOQA
2012-09-07 14:41:02 +00:00
import openerp
2013-02-18 17:55:59 +00:00
import openerp . exceptions
2014-02-11 10:55:25 +00:00
from openerp import modules , tools
2012-11-28 18:37:01 +00:00
from openerp . modules . db import create_categories
2014-02-11 10:55:25 +00:00
from openerp . modules import get_module_resource
2012-03-22 11:21:34 +00:00
from openerp . tools . parse_version import parse_version
from openerp . tools . translate import _
2015-09-11 12:58:44 +00:00
from openerp . tools import html_sanitize
2014-07-06 14:44:26 +00:00
from openerp . osv import osv , orm , fields
from openerp import api , fields as fields2
2010-09-29 06:54:41 +00:00
2012-01-24 13:17:05 +00:00
_logger = logging . getLogger ( __name__ )
2011-07-04 13:34:31 +00:00
ACTION_DICT = {
2011-09-29 11:55:15 +00:00
' view_type ' : ' form ' ,
' view_mode ' : ' form ' ,
' res_model ' : ' base.module.upgrade ' ,
' target ' : ' new ' ,
' type ' : ' ir.actions.act_window ' ,
2012-09-11 13:00:37 +00:00
' nodestroy ' : True ,
2011-09-29 11:55:15 +00:00
}
2011-07-04 13:34:31 +00:00
2012-08-22 17:44:13 +00:00
def backup ( path , raise_exception = True ) :
path = os . path . normpath ( path )
if not os . path . exists ( path ) :
if not raise_exception :
return None
raise OSError ( ' path does not exists ' )
cnt = 1
while True :
bck = ' %s ~ %d ' % ( path , cnt )
if not os . path . exists ( bck ) :
shutil . move ( path , bck )
return bck
cnt + = 1
2006-12-07 13:41:40 +00:00
class module_category ( osv . osv ) :
2008-07-22 14:24:36 +00:00
_name = " ir.module.category "
2011-10-04 22:34:10 +00:00
_description = " Application "
2008-07-22 14:24:36 +00:00
2012-09-11 13:00:37 +00:00
def _module_nbr ( self , cr , uid , ids , prop , unknow_none , context ) :
2010-06-15 13:27:22 +00:00
cr . execute ( ' SELECT category_id, COUNT(*) \
FROM ir_module_module \
WHERE category_id IN % ( ids ) s \
OR category_id IN ( SELECT id \
FROM ir_module_category \
WHERE parent_id IN % ( ids ) s ) \
GROUP BY category_id ' , { ' ids ' : tuple(ids)}
2012-09-11 13:00:37 +00:00
)
2008-07-22 14:24:36 +00:00
result = dict ( cr . fetchall ( ) )
for id in ids :
2008-12-09 12:37:22 +00:00
cr . execute ( ' select id from ir_module_category where parent_id= %s ' , ( id , ) )
2010-11-12 10:41:14 +00:00
result [ id ] = sum ( [ result . get ( c , 0 ) for ( c , ) in cr . fetchall ( ) ] ,
result . get ( id , 0 ) )
2008-07-22 14:24:36 +00:00
return result
_columns = {
2014-05-21 09:52:05 +00:00
' name ' : fields . char ( " Name " , required = True , translate = True , select = True ) ,
2011-10-04 22:34:10 +00:00
' parent_id ' : fields . many2one ( ' ir.module.category ' , ' Parent Application ' , select = True ) ,
' child_ids ' : fields . one2many ( ' ir.module.category ' , ' parent_id ' , ' Child Applications ' ) ,
2012-01-04 13:30:27 +00:00
' module_nr ' : fields . function ( _module_nbr , string = ' Number of Modules ' , type = ' integer ' ) ,
2012-09-11 13:00:37 +00:00
' module_ids ' : fields . one2many ( ' ir.module.module ' , ' category_id ' , ' Modules ' ) ,
' description ' : fields . text ( " Description " , translate = True ) ,
' sequence ' : fields . integer ( ' Sequence ' ) ,
' visible ' : fields . boolean ( ' Visible ' ) ,
2014-05-21 09:52:05 +00:00
' xml_id ' : fields . function ( osv . osv . get_external_id , type = ' char ' , string = " External ID " ) ,
2008-07-22 14:24:36 +00:00
}
_order = ' name '
2006-12-07 13:41:40 +00:00
2011-10-05 14:23:15 +00:00
_defaults = {
2012-09-11 13:00:37 +00:00
' visible ' : 1 ,
2011-10-05 14:23:15 +00:00
}
2012-10-25 13:01:11 +00:00
class MyFilterMessages ( Transform ) :
"""
Custom docutils transform to remove ` system message ` for a document and
generate warnings .
( The standard filter removes them based on some ` report_level ` passed in
the ` settings_override ` dictionary , but if we use it , we can ' t see them
and generate warnings . )
"""
default_priority = 870
def apply ( self ) :
for node in self . document . traverse ( nodes . system_message ) :
_logger . warning ( " docutils ' system message present: %s " , str ( node ) )
node . parent . remove ( node )
class MyWriter ( Writer ) :
"""
Custom docutils html4ccs1 writer that doesn ' t add the warnings to the
output document .
"""
def get_transforms ( self ) :
return [ MyFilterMessages , writer_aux . Admonitions ]
2006-12-07 13:41:40 +00:00
class module ( osv . osv ) :
2008-07-22 14:24:36 +00:00
_name = " ir.module.module "
2012-07-16 20:35:12 +00:00
_rec_name = " shortdesc "
2008-07-22 14:24:36 +00:00
_description = " Module "
2013-12-17 10:57:05 +00:00
def fields_view_get ( self , cr , uid , view_id = None , view_type = ' form ' , context = None , toolbar = False , submenu = False ) :
res = super ( module , self ) . fields_view_get ( cr , uid , view_id = view_id , view_type = view_type , context = context , toolbar = toolbar , submenu = False )
2014-04-10 12:08:28 +00:00
result = self . pool . get ( ' ir.model.data ' ) . get_object_reference ( cr , uid , ' base ' , ' action_server_module_immediate_install ' ) [ 1 ]
2013-12-17 10:57:05 +00:00
if view_type == ' form ' :
if res . get ( ' toolbar ' , False ) :
2014-04-10 12:08:28 +00:00
list = [ rec for rec in res [ ' toolbar ' ] [ ' action ' ] if rec . get ( ' id ' , False ) != result ]
2013-12-17 10:57:05 +00:00
res [ ' toolbar ' ] = { ' action ' : list }
return res
2013-11-06 07:56:49 +00:00
2010-12-03 16:22:50 +00:00
@classmethod
def get_module_info ( cls , name ) :
2010-03-12 06:15:00 +00:00
info = { }
2008-07-22 14:24:36 +00:00
try :
2012-03-22 11:21:34 +00:00
info = modules . load_information_from_description_file ( name )
2010-09-29 07:03:46 +00:00
except Exception :
2012-01-24 13:17:05 +00:00
_logger . debug ( ' Error when trying to fetch informations for '
' module %s ' , name , exc_info = True )
2008-07-22 14:24:36 +00:00
return info
2012-08-20 06:27:34 +00:00
def _get_desc ( self , cr , uid , ids , field_name = None , arg = None , context = None ) :
2012-08-21 11:33:41 +00:00
res = dict . fromkeys ( ids , ' ' )
2012-08-20 06:27:34 +00:00
for module in self . browse ( cr , uid , ids , context = context ) :
2014-02-11 10:55:25 +00:00
path = get_module_resource ( module . name , ' static/description/index.html ' )
2013-03-25 17:36:25 +00:00
if path :
2013-06-28 10:04:07 +00:00
with tools . file_open ( path , ' rb ' ) as desc_file :
2013-05-30 13:51:47 +00:00
doc = desc_file . read ( )
html = lxml . html . document_fromstring ( doc )
2013-05-30 14:29:02 +00:00
for element , attribute , link , pos in html . iterlinks ( ) :
2013-05-30 15:27:41 +00:00
if element . get ( ' src ' ) and not ' // ' in element . get ( ' src ' ) and not ' static/ ' in element . get ( ' src ' ) :
2013-05-31 09:39:01 +00:00
element . set ( ' src ' , " / %s /static/description/ %s " % ( module . name , element . get ( ' src ' ) ) )
2015-09-11 14:16:27 +00:00
res [ module . id ] = html_sanitize ( lxml . html . tostring ( html ) )
2013-04-06 14:42:59 +00:00
else :
2014-07-08 12:39:24 +00:00
overrides = {
' embed_stylesheet ' : False ,
' doctitle_xform ' : False ,
' output_encoding ' : ' unicode ' ,
' xml_declaration ' : False ,
}
2014-07-09 06:47:37 +00:00
output = publish_string ( source = module . description or ' ' , settings_overrides = overrides , writer = MyWriter ( ) )
2015-09-11 14:16:27 +00:00
res [ module . id ] = html_sanitize ( output )
2012-08-20 06:27:34 +00:00
return res
2010-11-23 15:43:06 +00:00
def _get_latest_version ( self , cr , uid , ids , field_name = None , arg = None , context = None ) :
2012-08-24 14:23:23 +00:00
default_version = modules . adapt_version ( ' 1.0 ' )
res = dict . fromkeys ( ids , default_version )
2008-07-22 14:24:36 +00:00
for m in self . browse ( cr , uid , ids ) :
2012-08-24 14:23:23 +00:00
res [ m . id ] = self . get_module_info ( m . name ) . get ( ' version ' , default_version )
2008-07-22 14:24:36 +00:00
return res
2010-11-23 15:43:06 +00:00
def _get_views ( self , cr , uid , ids , field_name = None , arg = None , context = None ) :
2008-10-24 10:41:31 +00:00
res = { }
model_data_obj = self . pool . get ( ' ir.model.data ' )
2011-06-10 09:45:33 +00:00
dmodels = [ ]
if field_name is None or ' views_by_module ' in field_name :
dmodels . append ( ' ir.ui.view ' )
if field_name is None or ' reports_by_module ' in field_name :
dmodels . append ( ' ir.actions.report.xml ' )
if field_name is None or ' menus_by_module ' in field_name :
dmodels . append ( ' ir.ui.menu ' )
assert dmodels , " no models for %s " % field_name
2012-03-26 23:18:39 +00:00
2011-06-10 09:45:33 +00:00
for module_rec in self . browse ( cr , uid , ids , context = context ) :
2013-09-19 11:50:14 +00:00
res_mod_dic = res [ module_rec . id ] = {
2011-09-15 14:15:33 +00:00
' menus_by_module ' : [ ] ,
' reports_by_module ' : [ ] ,
2010-11-23 15:42:55 +00:00
' views_by_module ' : [ ]
2008-12-11 08:19:31 +00:00
}
2010-11-27 03:04:50 +00:00
2011-09-15 14:15:33 +00:00
# Skip uninstalled modules below, no data to find anyway.
2011-06-10 09:45:33 +00:00
if module_rec . state not in ( ' installed ' , ' to upgrade ' , ' to remove ' ) :
continue
# then, search and group ir.model.data records
2012-09-11 13:00:37 +00:00
imd_models = dict ( [ ( m , [ ] ) for m in dmodels ] )
imd_ids = model_data_obj . search ( cr , uid , [
( ' module ' , ' = ' , module_rec . name ) ,
( ' model ' , ' in ' , tuple ( dmodels ) )
] )
2011-06-10 09:45:33 +00:00
for imd_res in model_data_obj . read ( cr , uid , imd_ids , [ ' model ' , ' res_id ' ] , context = context ) :
imd_models [ imd_res [ ' model ' ] ] . append ( imd_res [ ' res_id ' ] )
2010-11-27 03:04:50 +00:00
2013-09-19 11:50:14 +00:00
def browse ( model ) :
M = self . pool [ model ]
# as this method is called before the module update, some xmlid may be invalid at this stage
# explictly filter records before reading them
ids = M . exists ( cr , uid , imd_models . get ( model , [ ] ) , context )
return M . browse ( cr , uid , ids , context )
def format_view ( v ) :
aa = v . inherit_id and ' * INHERIT ' or ' '
return ' %s %s ( %s ) ' % ( aa , v . name , v . type )
res_mod_dic [ ' views_by_module ' ] = map ( format_view , browse ( ' ir.ui.view ' ) )
res_mod_dic [ ' reports_by_module ' ] = map ( attrgetter ( ' name ' ) , browse ( ' ir.actions.report.xml ' ) )
res_mod_dic [ ' menus_by_module ' ] = map ( attrgetter ( ' complete_name ' ) , browse ( ' ir.ui.menu ' ) )
2012-09-11 13:00:37 +00:00
for key in res . iterkeys ( ) :
2011-09-15 14:15:33 +00:00
for k , v in res [ key ] . iteritems ( ) :
2010-11-23 15:42:55 +00:00
res [ key ] [ k ] = " \n " . join ( sorted ( v ) )
2008-10-24 10:41:31 +00:00
return res
2012-06-12 09:10:41 +00:00
def _get_icon_image ( self , cr , uid , ids , field_name = None , arg = None , context = None ) :
2012-06-05 13:11:52 +00:00
res = dict . fromkeys ( ids , ' ' )
for module in self . browse ( cr , uid , ids , context = context ) :
2014-02-11 10:55:25 +00:00
path = get_module_resource ( module . name , ' static ' , ' description ' , ' icon.png ' )
2012-06-05 13:11:52 +00:00
if path :
image_file = tools . file_open ( path , ' rb ' )
try :
res [ module . id ] = image_file . read ( ) . encode ( ' base64 ' )
finally :
image_file . close ( )
return res
2008-07-22 14:24:36 +00:00
_columns = {
2014-05-21 09:52:05 +00:00
' name ' : fields . char ( " Technical Name " , readonly = True , required = True , select = True ) ,
2010-09-21 11:01:56 +00:00
' category_id ' : fields . many2one ( ' ir.module.category ' , ' Category ' , readonly = True , select = True ) ,
2014-05-21 09:52:05 +00:00
' shortdesc ' : fields . char ( ' Module Name ' , readonly = True , translate = True ) ,
' summary ' : fields . char ( ' Summary ' , readonly = True , translate = True ) ,
2012-08-23 16:19:59 +00:00
' description ' : fields . text ( " Description " , readonly = True , translate = True ) ,
' description_html ' : fields . function ( _get_desc , string = ' Description HTML ' , type = ' html ' , method = True , readonly = True ) ,
2014-05-21 09:52:05 +00:00
' author ' : fields . char ( " Author " , readonly = True ) ,
' maintainer ' : fields . char ( ' Maintainer ' , readonly = True ) ,
2010-05-16 16:27:41 +00:00
' contributors ' : fields . text ( ' Contributors ' , readonly = True ) ,
2014-05-21 09:52:05 +00:00
' website ' : fields . char ( " Website " , readonly = True ) ,
2008-12-11 11:44:13 +00:00
2009-11-20 11:39:28 +00:00
# attention: Incorrect field names !!
2013-01-17 01:23:12 +00:00
# installed_version refers the latest version (the one on disk)
# latest_version refers the installed version (the one in database)
# published_version refers the version available on the repository
2012-09-11 13:00:37 +00:00
' installed_version ' : fields . function ( _get_latest_version , string = ' Latest Version ' , type = ' char ' ) ,
2014-05-21 09:52:05 +00:00
' latest_version ' : fields . char ( ' Installed Version ' , readonly = True ) ,
' published_version ' : fields . char ( ' Published Version ' , readonly = True ) ,
2009-11-20 11:39:28 +00:00
2014-05-21 09:52:05 +00:00
' url ' : fields . char ( ' URL ' , readonly = True ) ,
2011-12-18 20:47:31 +00:00
' sequence ' : fields . integer ( ' Sequence ' ) ,
2012-09-11 13:00:37 +00:00
' dependencies_id ' : fields . one2many ( ' ir.module.module.dependency ' , ' module_id ' , ' Dependencies ' , readonly = True ) ,
2012-01-30 09:52:38 +00:00
' auto_install ' : fields . boolean ( ' Automatic Installation ' ,
2012-09-11 13:00:37 +00:00
help = ' An auto-installable module is automatically installed by the '
' system when all its dependencies are satisfied. '
' If the module has no dependency, it is always installed. ' ) ,
2008-07-22 14:24:36 +00:00
' state ' : fields . selection ( [
2012-09-11 13:00:37 +00:00
( ' uninstallable ' , ' Not Installable ' ) ,
( ' uninstalled ' , ' Not Installed ' ) ,
( ' installed ' , ' Installed ' ) ,
( ' to upgrade ' , ' To be upgraded ' ) ,
( ' to remove ' , ' To be removed ' ) ,
( ' to install ' , ' To be installed ' )
2012-10-12 12:24:19 +00:00
] , string = ' Status ' , readonly = True , select = True ) ,
2012-04-23 10:54:39 +00:00
' demo ' : fields . boolean ( ' Demo Data ' , readonly = True ) ,
2008-11-03 18:19:28 +00:00
' license ' : fields . selection ( [
2012-09-11 13:00:37 +00:00
( ' GPL-2 ' , ' GPL Version 2 ' ) ,
( ' GPL-2 or any later version ' , ' GPL-2 or later version ' ) ,
( ' GPL-3 ' , ' GPL Version 3 ' ) ,
( ' GPL-3 or any later version ' , ' GPL-3 or later version ' ) ,
( ' AGPL-3 ' , ' Affero GPL-3 ' ) ,
2015-06-01 08:57:54 +00:00
( ' LGPL-3 ' , ' LGPL Version 3 ' ) ,
2012-09-11 13:00:37 +00:00
( ' Other OSI approved licence ' , ' Other OSI Approved Licence ' ) ,
( ' Other proprietary ' , ' Other Proprietary ' )
2012-08-23 16:19:59 +00:00
] , string = ' License ' , readonly = True ) ,
2012-01-04 13:30:27 +00:00
' menus_by_module ' : fields . function ( _get_views , string = ' Menus ' , type = ' text ' , multi = " meta " , store = True ) ,
' reports_by_module ' : fields . function ( _get_views , string = ' Reports ' , type = ' text ' , multi = " meta " , store = True ) ,
' views_by_module ' : fields . function ( _get_views , string = ' Views ' , type = ' text ' , multi = " meta " , store = True ) ,
2011-12-08 22:22:41 +00:00
' application ' : fields . boolean ( ' Application ' , readonly = True ) ,
2014-05-21 09:52:05 +00:00
' icon ' : fields . char ( ' Icon URL ' ) ,
2012-06-12 09:10:41 +00:00
' icon_image ' : fields . function ( _get_icon_image , string = ' Icon ' , type = " binary " ) ,
2008-07-22 14:24:36 +00:00
}
_defaults = {
2010-11-23 15:43:06 +00:00
' state ' : ' uninstalled ' ,
2011-12-18 20:47:31 +00:00
' sequence ' : 100 ,
2010-11-23 15:43:06 +00:00
' demo ' : False ,
' license ' : ' AGPL-3 ' ,
2008-07-22 14:24:36 +00:00
}
2011-12-18 20:47:31 +00:00
_order = ' sequence,name '
2008-07-22 14:24:36 +00:00
2010-11-18 16:47:21 +00:00
def _name_uniq_msg ( self , cr , uid , ids , context = None ) :
return _ ( ' The name of the module must be unique ! ' )
2008-07-22 14:24:36 +00:00
_sql_constraints = [
2012-09-11 13:00:37 +00:00
( ' name_uniq ' , ' UNIQUE (name) ' , _name_uniq_msg ) ,
2009-01-06 14:36:21 +00:00
]
2008-07-22 14:24:36 +00:00
def unlink ( self , cr , uid , ids , context = None ) :
if not ids :
return True
if isinstance ( ids , ( int , long ) ) :
ids = [ ids ]
2010-02-03 10:59:32 +00:00
mod_names = [ ]
2012-09-11 13:00:37 +00:00
for mod in self . read ( cr , uid , ids , [ ' state ' , ' name ' ] , context ) :
2008-07-22 14:24:36 +00:00
if mod [ ' state ' ] in ( ' installed ' , ' to upgrade ' , ' to remove ' , ' to install ' ) :
2012-09-11 13:00:37 +00:00
raise orm . except_orm ( _ ( ' Error ' ) , _ ( ' You try to remove a module that is installed or will be installed ' ) )
2009-12-31 10:12:09 +00:00
mod_names . append ( mod [ ' name ' ] )
#Removing the entry from ir_model_data
2011-12-18 20:47:31 +00:00
#ids_meta = self.pool.get('ir.model.data').search(cr, uid, [('name', '=', 'module_meta_information'), ('module', 'in', mod_names)])
2010-02-03 10:59:32 +00:00
2011-12-18 20:47:31 +00:00
#if ids_meta:
# self.pool.get('ir.model.data').unlink(cr, uid, ids_meta, context)
2009-12-31 10:12:09 +00:00
2008-07-22 14:24:36 +00:00
return super ( module , self ) . unlink ( cr , uid , ids , context = context )
2008-09-23 08:15:37 +00:00
2010-05-31 09:42:39 +00:00
@staticmethod
def _check_external_dependencies ( terp ) :
depends = terp . get ( ' external_dependencies ' )
if not depends :
return
for pydep in depends . get ( ' python ' , [ ] ) :
2015-07-03 09:55:58 +00:00
try :
importlib . import_module ( pydep )
except ImportError :
raise ImportError ( ' No module named %s ' % ( pydep , ) )
2010-05-31 09:42:39 +00:00
for binary in depends . get ( ' bin ' , [ ] ) :
if tools . find_in_path ( binary ) is None :
raise Exception ( ' Unable to find %r in path ' % ( binary , ) )
2010-12-03 16:22:50 +00:00
@classmethod
def check_external_dependencies ( cls , module_name , newstate = ' to install ' ) :
terp = cls . get_module_info ( module_name )
try :
cls . _check_external_dependencies ( terp )
except Exception , e :
if newstate == ' to install ' :
msg = _ ( ' Unable to install module " %s " because an external dependency is not met: %s ' )
elif newstate == ' to upgrade ' :
msg = _ ( ' Unable to upgrade module " %s " because an external dependency is not met: %s ' )
else :
msg = _ ( ' Unable to process module " %s " because an external dependency is not met: %s ' )
raise orm . except_orm ( _ ( ' Error ' ) , msg % ( module_name , e . args [ 0 ] ) )
2010-05-31 09:42:39 +00:00
2014-07-06 14:44:26 +00:00
@api.multi
def state_update ( self , newstate , states_to_update , level = 100 ) :
2012-09-11 13:00:37 +00:00
if level < 1 :
2008-08-20 12:00:54 +00:00
raise orm . except_orm ( _ ( ' Error ' ) , _ ( ' Recursion error in modules dependencies ! ' ) )
2014-07-06 14:44:26 +00:00
# whether some modules are installed with demo data
2008-09-03 08:06:01 +00:00
demo = False
2014-07-06 14:44:26 +00:00
for module in self :
# determine dependency modules to update/others
update_mods , ready_mods = self . browse ( ) , self . browse ( )
2008-07-22 14:24:36 +00:00
for dep in module . dependencies_id :
2008-08-20 12:00:54 +00:00
if dep . state == ' unknown ' :
2010-10-20 17:17:39 +00:00
raise orm . except_orm ( _ ( ' Error ' ) , _ ( " You try to install module ' %s ' that depends on module ' %s ' . \n But the latter module is not available in your system. " ) % ( module . name , dep . name , ) )
2014-07-06 14:44:26 +00:00
if dep . depend_id . state == newstate :
ready_mods + = dep . depend_id
2008-09-15 12:52:00 +00:00
else :
2014-07-06 14:44:26 +00:00
update_mods + = dep . depend_id
2010-10-08 13:20:28 +00:00
2014-07-06 14:44:26 +00:00
# update dependency modules that require it, and determine demo for module
update_demo = update_mods . state_update ( newstate , states_to_update , level = level - 1 )
module_demo = module . demo or update_demo or any ( mod . demo for mod in ready_mods )
demo = demo or module_demo
# check dependencies and update module itself
2010-12-03 16:22:50 +00:00
self . check_external_dependencies ( module . name , newstate )
2008-08-20 12:00:54 +00:00
if module . state in states_to_update :
2014-07-06 14:44:26 +00:00
module . write ( { ' state ' : newstate , ' demo ' : module_demo } )
2008-07-22 14:24:36 +00:00
return demo
2010-11-23 15:43:06 +00:00
def button_install ( self , cr , uid , ids , context = None ) :
2012-01-26 16:40:49 +00:00
# Mark the given modules to be installed.
2014-07-06 14:44:26 +00:00
self . state_update ( cr , uid , ids , ' to install ' , [ ' uninstalled ' ] , context = context )
2011-12-18 21:38:17 +00:00
2012-12-11 14:40:10 +00:00
# Mark (recursively) the newly satisfied modules to also be installed
2012-01-26 16:40:49 +00:00
# Select all auto-installable (but not yet installed) modules.
2012-09-11 13:00:37 +00:00
domain = [ ( ' state ' , ' = ' , ' uninstalled ' ) , ( ' auto_install ' , ' = ' , True ) ]
2012-01-26 16:40:49 +00:00
uninstalled_ids = self . search ( cr , uid , domain , context = context )
uninstalled_modules = self . browse ( cr , uid , uninstalled_ids , context = context )
2012-12-11 14:40:10 +00:00
# Keep those with:
# - all dependencies satisfied (installed or to be installed),
# - at least one dependency being 'to install'
satisfied_states = frozenset ( ( ' installed ' , ' to install ' , ' to upgrade ' ) )
2012-01-26 16:40:49 +00:00
def all_depencies_satisfied ( m ) :
2012-12-11 14:40:10 +00:00
states = set ( d . state for d in m . dependencies_id )
2012-12-11 18:53:10 +00:00
return states . issubset ( satisfied_states ) and ( ' to install ' in states )
2012-01-26 16:40:49 +00:00
to_install_modules = filter ( all_depencies_satisfied , uninstalled_modules )
to_install_ids = map ( lambda m : m . id , to_install_modules )
# Mark them to be installed.
if to_install_ids :
self . button_install ( cr , uid , to_install_ids , context = context )
2012-12-08 18:11:51 +00:00
2011-07-04 13:34:31 +00:00
return dict ( ACTION_DICT , name = _ ( ' Install ' ) )
2011-12-09 11:40:02 +00:00
def button_immediate_install ( self , cr , uid , ids , context = None ) :
""" Installs the selected module(s) immediately and fully,
returns the next res . config action to execute
: param ids : identifiers of the modules to install
: returns : next res . config item to execute
: rtype : dict [ str , object ]
"""
2012-08-08 10:43:54 +00:00
return self . _button_immediate_function ( cr , uid , ids , self . button_install , context = context )
2008-07-22 14:24:36 +00:00
2010-11-23 15:43:06 +00:00
def button_install_cancel ( self , cr , uid , ids , context = None ) :
2012-09-11 13:00:37 +00:00
self . write ( cr , uid , ids , { ' state ' : ' uninstalled ' , ' demo ' : False } )
2008-07-22 14:24:36 +00:00
return True
2012-02-29 13:53:43 +00:00
def module_uninstall ( self , cr , uid , ids , context = None ) :
2012-03-30 16:34:22 +00:00
""" Perform the various steps required to uninstall a module completely
including the deletion of all database structures created by the module :
tables , columns , constraints , etc . """
2012-03-26 23:18:39 +00:00
ir_model_data = self . pool . get ( ' ir.model.data ' )
modules_to_remove = [ m . name for m in self . browse ( cr , uid , ids , context ) ]
2012-06-19 15:16:26 +00:00
ir_model_data . _module_data_uninstall ( cr , uid , modules_to_remove , context )
2015-07-29 10:00:15 +00:00
self . write ( cr , uid , ids , { ' state ' : ' uninstalled ' , ' latest_version ' : False } )
2012-03-26 23:18:39 +00:00
return True
2012-03-09 12:47:53 +00:00
2012-03-26 23:18:39 +00:00
def downstream_dependencies ( self , cr , uid , ids , known_dep_ids = None ,
2012-09-11 13:00:37 +00:00
exclude_states = [ ' uninstalled ' , ' uninstallable ' , ' to remove ' ] ,
2012-03-26 23:18:39 +00:00
context = None ) :
""" Return the ids of all modules that directly or indirectly depend
on the given module ` ids ` , and that satisfy the ` exclude_states `
filter """
2012-09-11 13:00:37 +00:00
if not ids :
return [ ]
2012-03-26 23:18:39 +00:00
known_dep_ids = set ( known_dep_ids or [ ] )
cr . execute ( ''' SELECT DISTINCT m.id
FROM
ir_module_module_dependency d
JOIN
ir_module_module m ON ( d . module_id = m . id )
WHERE
d . name IN ( SELECT name from ir_module_module where id in % s ) AND
m . state NOT IN % s AND
m . id NOT IN % s ''' ,
2012-09-11 13:00:37 +00:00
( tuple ( ids ) , tuple ( exclude_states ) , tuple ( known_dep_ids or ids ) ) )
2012-03-26 23:18:39 +00:00
new_dep_ids = set ( [ m [ 0 ] for m in cr . fetchall ( ) ] )
missing_mod_ids = new_dep_ids - known_dep_ids
known_dep_ids | = new_dep_ids
if missing_mod_ids :
known_dep_ids | = set ( self . downstream_dependencies ( cr , uid , list ( missing_mod_ids ) ,
2012-09-11 13:00:37 +00:00
known_dep_ids , exclude_states , context ) )
2012-03-26 23:18:39 +00:00
return list ( known_dep_ids )
2012-03-09 12:47:53 +00:00
2012-08-08 10:43:54 +00:00
def _button_immediate_function ( self , cr , uid , ids , function , context = None ) :
function ( cr , uid , ids , context = context )
cr . commit ( )
2014-10-02 08:36:42 +00:00
api . Environment . reset ( )
2013-03-27 11:10:14 +00:00
registry = openerp . modules . registry . RegistryManager . new ( cr . dbname , update_module = True )
2012-08-08 10:43:54 +00:00
2013-03-27 11:10:14 +00:00
config = registry [ ' res.config ' ] . next ( cr , uid , [ ] , context = context ) or { }
2012-10-24 08:44:09 +00:00
if config . get ( ' type ' ) not in ( ' ir.actions.act_window_close ' , ) :
2012-08-08 10:43:54 +00:00
return config
# reload the client; open the first available root menu
2013-03-27 11:10:14 +00:00
menu_obj = registry [ ' ir.ui.menu ' ]
2012-08-08 10:43:54 +00:00
menu_ids = menu_obj . search ( cr , uid , [ ( ' parent_id ' , ' = ' , False ) ] , context = context )
return {
2012-09-11 13:00:37 +00:00
' type ' : ' ir.actions.client ' ,
' tag ' : ' reload ' ,
' params ' : { ' menu_id ' : menu_ids and menu_ids [ 0 ] or False }
2012-08-08 10:43:54 +00:00
}
2014-06-20 15:36:26 +00:00
#TODO remove me in master, not called anymore
2012-08-08 10:43:54 +00:00
def button_immediate_uninstall ( self , cr , uid , ids , context = None ) :
"""
Uninstall the selected module ( s ) immediately and fully ,
returns the next res . config action to execute
"""
return self . _button_immediate_function ( cr , uid , ids , self . button_uninstall , context = context )
2010-11-23 15:43:06 +00:00
def button_uninstall ( self , cr , uid , ids , context = None ) :
2012-08-08 10:43:54 +00:00
if any ( m . name == ' base ' for m in self . browse ( cr , uid , ids , context = context ) ) :
2012-03-26 23:18:39 +00:00
raise orm . except_orm ( _ ( ' Error ' ) , _ ( " The `base` module cannot be uninstalled " ) )
dep_ids = self . downstream_dependencies ( cr , uid , ids , context = context )
self . write ( cr , uid , ids + dep_ids , { ' state ' : ' to remove ' } )
2011-07-04 13:34:31 +00:00
return dict ( ACTION_DICT , name = _ ( ' Uninstall ' ) )
2008-07-22 14:24:36 +00:00
2010-11-23 15:43:06 +00:00
def button_uninstall_cancel ( self , cr , uid , ids , context = None ) :
2008-07-22 14:24:36 +00:00
self . write ( cr , uid , ids , { ' state ' : ' installed ' } )
return True
2008-09-17 15:55:18 +00:00
2012-08-08 10:43:54 +00:00
def button_immediate_upgrade ( self , cr , uid , ids , context = None ) :
"""
Upgrade the selected module ( s ) immediately and fully ,
return the next res . config action to execute
"""
return self . _button_immediate_function ( cr , uid , ids , self . button_upgrade , context = context )
2008-07-22 14:24:36 +00:00
def button_upgrade ( self , cr , uid , ids , context = None ) :
2008-09-17 15:55:18 +00:00
depobj = self . pool . get ( ' ir.module.module.dependency ' )
2014-07-06 14:44:26 +00:00
todo = list ( self . browse ( cr , uid , ids , context = context ) )
2010-03-16 06:48:12 +00:00
self . update_list ( cr , uid )
2008-09-17 15:55:18 +00:00
i = 0
2012-09-11 13:00:37 +00:00
while i < len ( todo ) :
2008-09-17 15:55:18 +00:00
mod = todo [ i ]
i + = 1
2012-09-11 13:00:37 +00:00
if mod . state not in ( ' installed ' , ' to upgrade ' ) :
raise orm . except_orm ( _ ( ' Error ' ) , _ ( " Can not upgrade module ' %s ' . It is not installed. " ) % ( mod . name , ) )
2010-12-03 16:22:50 +00:00
self . check_external_dependencies ( mod . name , ' to upgrade ' )
2008-09-17 15:55:18 +00:00
iids = depobj . search ( cr , uid , [ ( ' name ' , ' = ' , mod . name ) ] , context = context )
for dep in depobj . browse ( cr , uid , iids , context = context ) :
2012-09-11 13:00:37 +00:00
if dep . module_id . state == ' installed ' and dep . module_id not in todo :
2008-09-17 15:55:18 +00:00
todo . append ( dep . module_id )
2009-11-20 11:39:28 +00:00
2008-12-11 14:54:20 +00:00
ids = map ( lambda x : x . id , todo )
2012-09-11 13:00:37 +00:00
self . write ( cr , uid , ids , { ' state ' : ' to upgrade ' } , context = context )
2009-11-20 11:39:28 +00:00
2008-12-11 16:07:46 +00:00
to_install = [ ]
for mod in todo :
for dep in mod . dependencies_id :
if dep . state == ' unknown ' :
raise orm . except_orm ( _ ( ' Error ' ) , _ ( ' You try to upgrade a module that depends on the module: %s . \n But this module is not available in your system. ' ) % ( dep . name , ) )
if dep . state == ' uninstalled ' :
2012-09-11 13:00:37 +00:00
ids2 = self . search ( cr , uid , [ ( ' name ' , ' = ' , dep . name ) ] )
2008-12-11 16:07:46 +00:00
to_install . extend ( ids2 )
2009-11-20 11:39:28 +00:00
2008-12-11 16:07:46 +00:00
self . button_install ( cr , uid , to_install , context = context )
2012-07-02 11:29:18 +00:00
return dict ( ACTION_DICT , name = _ ( ' Apply Schedule Upgrade ' ) )
2008-09-17 15:55:18 +00:00
2010-11-23 15:43:06 +00:00
def button_upgrade_cancel ( self , cr , uid , ids , context = None ) :
2008-07-22 14:24:36 +00:00
self . write ( cr , uid , ids , { ' state ' : ' installed ' } )
return True
2011-07-04 13:34:31 +00:00
2008-09-04 13:54:32 +00:00
def button_update_translations ( self , cr , uid , ids , context = None ) :
self . update_translations ( cr , uid , ids )
2008-07-22 14:24:36 +00:00
return True
2010-05-16 16:27:41 +00:00
@staticmethod
def get_values_from_terp ( terp ) :
return {
' description ' : terp . get ( ' description ' , ' ' ) ,
' shortdesc ' : terp . get ( ' name ' , ' ' ) ,
' author ' : terp . get ( ' author ' , ' Unknown ' ) ,
' maintainer ' : terp . get ( ' maintainer ' , False ) ,
2010-05-31 12:19:18 +00:00
' contributors ' : ' , ' . join ( terp . get ( ' contributors ' , [ ] ) ) or False ,
2010-05-16 16:27:41 +00:00
' website ' : terp . get ( ' website ' , ' ' ) ,
2010-11-27 03:04:50 +00:00
' license ' : terp . get ( ' license ' , ' AGPL-3 ' ) ,
2012-01-07 04:17:45 +00:00
' sequence ' : terp . get ( ' sequence ' , 100 ) ,
' application ' : terp . get ( ' application ' , False ) ,
2012-01-30 09:52:38 +00:00
' auto_install ' : terp . get ( ' auto_install ' , False ) ,
2012-03-01 01:47:08 +00:00
' icon ' : terp . get ( ' icon ' , False ) ,
2012-07-17 05:39:45 +00:00
' summary ' : terp . get ( ' summary ' , ' ' ) ,
2010-05-16 16:27:41 +00:00
}
2014-07-23 12:42:04 +00:00
def create ( self , cr , uid , vals , context = None ) :
new_id = super ( module , self ) . create ( cr , uid , vals , context = context )
module_metadata = {
' name ' : ' module_ %s ' % vals [ ' name ' ] ,
' model ' : ' ir.module.module ' ,
' module ' : ' base ' ,
' res_id ' : new_id ,
' noupdate ' : True ,
}
self . pool [ ' ir.model.data ' ] . create ( cr , uid , module_metadata )
return new_id
2008-07-22 14:24:36 +00:00
# update the list of available packages
2011-11-07 15:19:49 +00:00
def update_list ( self , cr , uid , context = None ) :
2012-08-24 14:23:23 +00:00
res = [ 0 , 0 ] # [update, add]
2008-07-22 14:24:36 +00:00
2012-08-24 14:23:23 +00:00
default_version = modules . adapt_version ( ' 1.0 ' )
2010-11-27 03:04:50 +00:00
known_mods = self . browse ( cr , uid , self . search ( cr , uid , [ ] ) )
known_mods_names = dict ( [ ( m . name , m ) for m in known_mods ] )
# iterate through detected modules and update/create them in db
2012-03-22 11:21:34 +00:00
for mod_name in modules . get_modules ( ) :
2010-11-27 03:04:50 +00:00
mod = known_mods_names . get ( mod_name )
2010-05-16 16:27:41 +00:00
terp = self . get_module_info ( mod_name )
values = self . get_values_from_terp ( terp )
2010-11-27 03:04:50 +00:00
if mod :
updated_values = { }
for key in values :
old = getattr ( mod , key )
2012-03-26 23:18:39 +00:00
updated = isinstance ( values [ key ] , basestring ) and tools . ustr ( values [ key ] ) or values [ key ]
2014-07-06 14:44:26 +00:00
if ( old or updated ) and updated != old :
2010-11-27 03:04:50 +00:00
updated_values [ key ] = values [ key ]
2008-07-22 14:24:36 +00:00
if terp . get ( ' installable ' , True ) and mod . state == ' uninstallable ' :
2010-11-27 03:04:50 +00:00
updated_values [ ' state ' ] = ' uninstalled '
2012-08-24 14:23:23 +00:00
if parse_version ( terp . get ( ' version ' , default_version ) ) > parse_version ( mod . latest_version or default_version ) :
2008-07-22 14:24:36 +00:00
res [ 0 ] + = 1
2010-11-27 03:04:50 +00:00
if updated_values :
self . write ( cr , uid , mod . id , updated_values )
2010-05-16 16:27:41 +00:00
else :
2012-03-22 11:21:34 +00:00
mod_path = modules . get_module_path ( mod_name )
2010-05-16 16:27:41 +00:00
if not mod_path :
continue
2008-07-22 14:24:36 +00:00
if not terp or not terp . get ( ' installable ' , True ) :
continue
2010-05-16 16:27:41 +00:00
id = self . create ( cr , uid , dict ( name = mod_name , state = ' uninstalled ' , * * values ) )
2010-11-27 03:04:50 +00:00
mod = self . browse ( cr , uid , id )
2008-07-22 14:24:36 +00:00
res [ 1 ] + = 1
2010-11-27 03:04:50 +00:00
self . _update_dependencies ( cr , uid , mod , terp . get ( ' depends ' , [ ] ) )
self . _update_category ( cr , uid , mod , terp . get ( ' category ' , ' Uncategorized ' ) )
2008-07-22 14:24:36 +00:00
2012-12-19 02:59:08 +00:00
# Trigger load_addons if new module have been discovered it exists on
# wsgi handlers, so they can react accordingly
if tuple ( res ) != ( 0 , 0 ) :
for handler in openerp . service . wsgi_server . module_handlers :
2013-09-19 11:50:14 +00:00
if hasattr ( handler , ' load_addons ' ) :
2012-12-19 02:59:08 +00:00
handler . load_addons ( )
2008-07-22 14:24:36 +00:00
return res
def download ( self , cr , uid , ids , download = True , context = None ) :
2014-04-10 09:58:17 +00:00
return [ ]
2008-07-22 14:24:36 +00:00
2012-08-22 17:44:13 +00:00
def install_from_urls ( self , cr , uid , urls , context = None ) :
2013-02-18 17:55:59 +00:00
if not self . pool [ ' res.users ' ] . has_group ( cr , uid , ' base.group_system ' ) :
raise openerp . exceptions . AccessDenied ( )
apps_server = urlparse . urlparse ( self . get_apps_server ( cr , uid , context = context ) )
2014-10-21 10:48:19 +00:00
OPENERP = openerp . release . product_name . lower ( )
2012-08-22 17:44:13 +00:00
tmp = tempfile . mkdtemp ( )
2013-01-17 13:29:24 +00:00
_logger . debug ( ' Install from url: %r ' , urls )
2012-08-22 17:44:13 +00:00
try :
2013-01-17 01:23:12 +00:00
# 1. Download & unzip missing modules
2012-10-02 13:25:35 +00:00
for module_name , url in urls . items ( ) :
if not url :
continue # nothing to download, local version is already the last one
2013-02-18 17:55:59 +00:00
up = urlparse . urlparse ( url )
if up . scheme != apps_server . scheme or up . netloc != apps_server . netloc :
raise openerp . exceptions . AccessDenied ( )
2012-08-22 17:44:13 +00:00
try :
2013-01-17 01:23:12 +00:00
_logger . info ( ' Downloading module ` %s ` from OpenERP Apps ' , module_name )
2012-10-02 13:25:35 +00:00
content = urllib2 . urlopen ( url ) . read ( )
2013-01-17 01:23:12 +00:00
except Exception :
_logger . exception ( ' Failed to fetch module %s ' , module_name )
raise osv . except_osv ( _ ( ' Module not found ' ) ,
_ ( ' The ` %s ` module appears to be unavailable at the moment, please try again later. ' ) % module_name )
2012-08-22 17:44:13 +00:00
else :
2012-09-11 10:38:53 +00:00
zipfile . ZipFile ( StringIO ( content ) ) . extractall ( tmp )
2012-08-22 17:44:13 +00:00
assert os . path . isdir ( os . path . join ( tmp , module_name ) )
2013-01-17 13:29:24 +00:00
# 2a. Copy/Replace module source in addons path
2013-01-17 01:23:12 +00:00
for module_name , url in urls . items ( ) :
if module_name == OPENERP or not url :
continue # OPENERP is special case, handled below, and no URL means local module
2012-08-22 17:44:13 +00:00
module_path = modules . get_module_path ( module_name , downloaded = True , display_warning = False )
bck = backup ( module_path , False )
2013-01-17 13:29:24 +00:00
_logger . info ( ' Copy downloaded module ` %s ` to ` %s ` ' , module_name , module_path )
2012-08-22 17:44:13 +00:00
shutil . move ( os . path . join ( tmp , module_name ) , module_path )
if bck :
shutil . rmtree ( bck )
2013-01-17 01:23:12 +00:00
# 2b. Copy/Replace server+base module source if downloaded
2012-10-02 10:06:39 +00:00
if urls . get ( OPENERP , None ) :
2013-01-17 01:23:12 +00:00
# special case. it contains the server and the base module.
2012-09-07 14:41:02 +00:00
# extract path is not the same
base_path = os . path . dirname ( modules . get_module_path ( ' base ' ) )
2012-10-02 10:06:39 +00:00
# copy all modules in the SERVER/openerp/addons directory to the new "openerp" module (except base itself)
2012-09-07 14:41:02 +00:00
for d in os . listdir ( base_path ) :
if d != ' base ' and os . path . isdir ( os . path . join ( base_path , d ) ) :
2012-10-02 10:06:39 +00:00
destdir = os . path . join ( tmp , OPENERP , ' addons ' , d ) # XXX 'openerp' subdirectory ?
2012-09-07 14:41:02 +00:00
shutil . copytree ( os . path . join ( base_path , d ) , destdir )
2012-10-02 10:06:39 +00:00
# then replace the server by the new "base" module
2012-09-07 14:41:02 +00:00
server_dir = openerp . tools . config [ ' root_path ' ] # XXX or dirname()
bck = backup ( server_dir )
2013-01-17 13:29:24 +00:00
_logger . info ( ' Copy downloaded module `openerp` to ` %s ` ' , server_dir )
2012-10-02 10:06:39 +00:00
shutil . move ( os . path . join ( tmp , OPENERP ) , server_dir )
2012-09-07 14:41:02 +00:00
#if bck:
# shutil.rmtree(bck)
2012-08-22 17:44:13 +00:00
self . update_list ( cr , uid , context = context )
2013-01-17 13:29:24 +00:00
with_urls = [ m for m , u in urls . items ( ) if u ]
downloaded_ids = self . search ( cr , uid , [ ( ' name ' , ' in ' , with_urls ) ] , context = context )
already_installed = self . search ( cr , uid , [ ( ' id ' , ' in ' , downloaded_ids ) , ( ' state ' , ' = ' , ' installed ' ) ] , context = context )
to_install_ids = self . search ( cr , uid , [ ( ' name ' , ' in ' , urls . keys ( ) ) , ( ' state ' , ' = ' , ' uninstalled ' ) ] , context = context )
post_install_action = self . button_immediate_install ( cr , uid , to_install_ids , context = context )
2016-11-14 11:52:22 +00:00
if already_installed or to_install_ids :
2013-01-17 13:29:24 +00:00
# in this case, force server restart to reload python code...
2012-09-07 14:41:02 +00:00
cr . commit ( )
2013-10-05 22:18:29 +00:00
openerp . service . server . restart ( )
2012-09-28 11:31:43 +00:00
return {
' type ' : ' ir.actions.client ' ,
2012-10-31 12:03:01 +00:00
' tag ' : ' home ' ,
' params ' : { ' wait ' : True } ,
2012-09-28 11:31:43 +00:00
}
2013-01-17 13:29:24 +00:00
return post_install_action
2012-09-05 13:21:39 +00:00
finally :
shutil . rmtree ( tmp )
2012-08-22 17:44:13 +00:00
2013-02-18 17:55:59 +00:00
def get_apps_server ( self , cr , uid , context = None ) :
return tools . config . get ( ' apps_server ' , ' https://apps.openerp.com/apps ' )
2012-09-11 12:02:57 +00:00
2010-11-27 03:04:50 +00:00
def _update_dependencies ( self , cr , uid , mod_browse , depends = None ) :
2010-11-23 15:43:06 +00:00
if depends is None :
depends = [ ]
2010-11-27 03:04:50 +00:00
existing = set ( x . name for x in mod_browse . dependencies_id )
needed = set ( depends )
for dep in ( needed - existing ) :
cr . execute ( ' INSERT INTO ir_module_module_dependency (module_id, name) values ( %s , %s ) ' , ( mod_browse . id , dep ) )
for dep in ( existing - needed ) :
cr . execute ( ' DELETE FROM ir_module_module_dependency WHERE module_id = %s and name = %s ' , ( mod_browse . id , dep ) )
2014-07-06 14:44:26 +00:00
self . invalidate_cache ( cr , uid , [ ' dependencies_id ' ] , [ mod_browse . id ] )
2010-11-27 03:04:50 +00:00
def _update_category ( self , cr , uid , mod_browse , category = ' Uncategorized ' ) :
current_category = mod_browse . category_id
current_category_path = [ ]
while current_category :
current_category_path . insert ( 0 , current_category . name )
current_category = current_category . parent_id
2008-07-22 14:24:36 +00:00
categs = category . split ( ' / ' )
2010-11-27 03:04:50 +00:00
if categs != current_category_path :
2012-11-28 18:37:01 +00:00
cat_id = create_categories ( cr , categs )
mod_browse . write ( { ' category_id ' : cat_id } )
2008-08-26 10:41:13 +00:00
2011-05-12 13:45:53 +00:00
def update_translations ( self , cr , uid , ids , filter_lang = None , context = None ) :
2008-09-04 13:54:32 +00:00
if not filter_lang :
2012-09-13 14:29:20 +00:00
res_lang = self . pool . get ( ' res.lang ' )
lang_ids = res_lang . search ( cr , uid , [ ( ' translatable ' , ' = ' , True ) ] )
filter_lang = [ lang . code for lang in res_lang . browse ( cr , uid , lang_ids ) ]
2008-09-04 13:54:32 +00:00
elif not isinstance ( filter_lang , ( list , tuple ) ) :
filter_lang = [ filter_lang ]
2012-09-13 14:29:20 +00:00
modules = [ m . name for m in self . browse ( cr , uid , ids ) if m . state == ' installed ' ]
2013-12-30 12:53:07 +00:00
self . pool . get ( ' ir.translation ' ) . load_module_terms ( cr , modules , filter_lang , context = context )
2008-09-04 13:54:32 +00:00
2009-01-07 15:53:45 +00:00
def check ( self , cr , uid , ids , context = None ) :
for mod in self . browse ( cr , uid , ids , context = context ) :
if not mod . description :
2012-02-02 09:26:34 +00:00
_logger . warning ( ' module %s : description is empty ! ' , mod . name )
2008-12-22 23:58:21 +00:00
2014-07-06 14:44:26 +00:00
DEP_STATES = [
( ' uninstallable ' , ' Uninstallable ' ) ,
( ' uninstalled ' , ' Not Installed ' ) ,
( ' installed ' , ' Installed ' ) ,
( ' to upgrade ' , ' To be upgraded ' ) ,
( ' to remove ' , ' To be removed ' ) ,
( ' to install ' , ' To be installed ' ) ,
( ' unknown ' , ' Unknown ' ) ,
]
class module_dependency ( osv . Model ) :
2008-07-22 14:24:36 +00:00
_name = " ir.module.module.dependency "
_description = " Module dependency "
2014-07-06 14:44:26 +00:00
# the dependency name
name = fields2 . Char ( index = True )
2008-07-22 14:24:36 +00:00
2014-07-06 14:44:26 +00:00
# the module that depends on it
module_id = fields2 . Many2one ( ' ir.module.module ' , ' Module ' , ondelete = ' cascade ' )
2012-03-30 22:20:23 +00:00
2014-07-06 14:44:26 +00:00
# the module corresponding to the dependency, and its status
depend_id = fields2 . Many2one ( ' ir.module.module ' , ' Dependency ' , compute = ' _compute_depend ' )
state = fields2 . Selection ( DEP_STATES , string = ' Status ' , compute = ' _compute_state ' )
@api.multi
@api.depends ( ' name ' )
def _compute_depend ( self ) :
# retrieve all modules corresponding to the dependency names
names = list ( set ( dep . name for dep in self ) )
mods = self . env [ ' ir.module.module ' ] . search ( [ ( ' name ' , ' in ' , names ) ] )
# index modules by name, and assign dependencies
name_mod = dict ( ( mod . name , mod ) for mod in mods )
for dep in self :
dep . depend_id = name_mod . get ( dep . name )
@api.one
@api.depends ( ' depend_id.state ' )
def _compute_state ( self ) :
self . state = self . depend_id . state or ' unknown '
2012-03-30 22:20:23 +00:00
2011-11-22 08:58:48 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: