diff options
| author | Nicolas Vanhoren <niv@openerp.com> | 2010-12-08 18:03:50 +0100 |
|---|---|---|
| committer | Olivier Dony <odo@openerp.com> | 2010-12-08 18:03:50 +0100 |
| commit | 2c3cee033d3c2cc9100d315dadb145525d0f808e (patch) | |
| tree | 653d9da03ff1e56f57734602de63dcd820803055 | |
| parent | cfa513123a98ea098bcdb042f4a0fe590a4a5bff (diff) | |
| parent | 402236d40dae999660007dec4e4954d36f0426f7 (diff) | |
[MERGE] refactor maintenance.contract into publisher_warranty.contract + add system logs scheduler
bzr revid: odo@openerp.com-20101208170350-p8tek7dk7wdtnzvb
| -rw-r--r-- | .bzrignore | 3 | ||||
| -rw-r--r-- | bin/addons/base/__init__.py | 2 | ||||
| -rw-r--r-- | bin/addons/base/__openerp__.py | 3 | ||||
| -rw-r--r-- | bin/addons/base/ir/__init__.py | 1 | ||||
| -rw-r--r-- | bin/addons/base/ir/ir_config_parameter.py | 101 | ||||
| -rw-r--r-- | bin/addons/base/ir/ir_cron.py | 3 | ||||
| -rw-r--r-- | bin/addons/base/maintenance/maintenance.py | 206 | ||||
| -rw-r--r-- | bin/addons/base/maintenance/maintenance_security.xml | 6 | ||||
| -rw-r--r-- | bin/addons/base/maintenance/maintenance_view.xml | 131 | ||||
| -rw-r--r-- | bin/addons/base/publisher_warranty/__init__.py (renamed from bin/addons/base/maintenance/__init__.py) | 2 | ||||
| -rw-r--r-- | bin/addons/base/publisher_warranty/publisher_warranty.py | 323 | ||||
| -rw-r--r-- | bin/addons/base/publisher_warranty/publisher_warranty_data.xml | 20 | ||||
| -rw-r--r-- | bin/addons/base/publisher_warranty/publisher_warranty_view.xml | 146 | ||||
| -rw-r--r-- | bin/addons/base/res/res_log.py | 13 | ||||
| -rw-r--r-- | bin/addons/base/res/res_log_view.xml | 2 | ||||
| -rw-r--r-- | bin/addons/base/security/ir.model.access.csv | 5 | ||||
| -rw-r--r-- | bin/tools/config.py | 24 | ||||
| -rw-r--r-- | bin/tools/maintenance.py | 69 |
18 files changed, 627 insertions, 433 deletions
diff --git a/.bzrignore b/.bzrignore index 5581ee20f94..f67a6e2c6b6 100644 --- a/.bzrignore +++ b/.bzrignore @@ -18,3 +18,6 @@ bin/python2.6 build/ bin/yolk bin/pil*.py +.project +.pydevproject +.settings diff --git a/bin/addons/base/__init__.py b/bin/addons/base/__init__.py index bf315934c6d..fe483c40602 100644 --- a/bin/addons/base/__init__.py +++ b/bin/addons/base/__init__.py @@ -22,7 +22,7 @@ import ir import module import res -import maintenance +import publisher_warranty # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/bin/addons/base/__openerp__.py b/bin/addons/base/__openerp__.py index d57a8878199..eefaf9f4442 100644 --- a/bin/addons/base/__openerp__.py +++ b/bin/addons/base/__openerp__.py @@ -71,11 +71,12 @@ 'res/ir_property_view.xml', 'security/base_security.xml', - 'maintenance/maintenance_view.xml', + 'publisher_warranty/publisher_warranty_view.xml', 'security/ir.model.access.csv', 'res/res_widget_view.xml', 'res/res_widget_data.xml', + 'publisher_warranty/publisher_warranty_data.xml', ], 'demo_xml': [ 'base_demo.xml', diff --git a/bin/addons/base/ir/__init__.py b/bin/addons/base/ir/__init__.py index 145a167fdc2..9b4eb96df5f 100644 --- a/bin/addons/base/ir/__init__.py +++ b/bin/addons/base/ir/__init__.py @@ -34,6 +34,7 @@ import ir_exports import workflow import ir_rule import wizard +import ir_config_parameter import osv_memory_autovacuum # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/bin/addons/base/ir/ir_config_parameter.py b/bin/addons/base/ir/ir_config_parameter.py new file mode 100644 index 00000000000..b1688b9a669 --- /dev/null +++ b/bin/addons/base/ir/ir_config_parameter.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). +# +# This program is free software: you can redistribute it and/or modify +# 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. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################## +""" +A module to store some configuration parameters relative to a whole database. +""" + +from osv import osv,fields +import uuid +import datetime +from tools import misc + +""" +A dictionary holding some configuration parameters to be initialized when the database is created. +""" +_default_parameters = { + "database.uuid": lambda: str(uuid.uuid1()), + "database.create_date": lambda: datetime.datetime.now().strftime(misc.DEFAULT_SERVER_DATETIME_FORMAT), +} + +class ir_config_parameter(osv.osv): + """ An osv to old configuration parameters for a given database. + + To be short, it's just a global dictionary of strings stored in a table. """ + + _name = 'ir.config_parameter' + + _columns = { + # The key of the configuration parameter. + 'key': fields.char('Key', size=256, required=True, select=1), + # The value of the configuration parameter. + 'value': fields.text('Value', required=True), + } + + _sql_constraints = [ + ('key_uniq', 'unique (key)', 'Key must be unique.') + ] + + def init(self, cr): + """ + Initializes the parameters listed in _default_parameters. + """ + for key, func in _default_parameters.iteritems(): + ids = self.search(cr, 1, [('key','=',key)]) + if not ids: + self.set_param(cr, 1, key, func()) + + def get_param(self, cr, uid, key, context=None): + """ Get the value of a parameter. + + @param key: The key of the parameter. + @type key: string + @return: The value of the parameter, False if it does not exist. + @rtype: string + """ + ids = self.search(cr, uid, [('key','=',key)], context=context) + if not ids: + return False + param = self.browse(cr, uid, ids[0], context=context) + value = param.value + return value + + def set_param(self, cr, uid, key, value, context=None): + """ Set the value of a parameter. + + @param key: The key of the parameter. + @type key: string + @param value: The value of the parameter. + @type value: string + @return: Return the previous value of the parameter of False if it did + not existed. + @rtype: string + """ + ids = self.search(cr, uid, [('key','=',key)], context=context) + if ids: + param = self.browse(cr, uid, ids[0], context=context) + old = param.value + self.write(cr, uid, ids, {'value': value}, context=context) + return old + else: + self.create(cr, uid, {'key': key, 'value': value}, context=context) + return False + +ir_config_parameter() diff --git a/bin/addons/base/ir/ir_cron.py b/bin/addons/base/ir/ir_cron.py index 7e5a73b4aba..391833d2fbe 100644 --- a/bin/addons/base/ir/ir_cron.py +++ b/bin/addons/base/ir/ir_cron.py @@ -144,7 +144,8 @@ class ir_cron(osv.osv, netsvc.Agent): def restart(self, dbname): self.cancel(dbname) - self._poolJobs(dbname) + # Reschedule cron processing job asap, but not in the current thread + self.setAlarm(self._poolJobs, time.time(), dbname, dbname) def create(self, cr, uid, vals, context=None): res = super(ir_cron, self).create(cr, uid, vals, context=context) diff --git a/bin/addons/base/maintenance/maintenance.py b/bin/addons/base/maintenance/maintenance.py deleted file mode 100644 index 389d915512f..00000000000 --- a/bin/addons/base/maintenance/maintenance.py +++ /dev/null @@ -1,206 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). -# -# This program is free software: you can redistribute it and/or modify -# 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. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -############################################################################## - -from osv import osv, fields -import pooler -import time -import netsvc - -from tools.misc import debug -from tools.misc import ustr -from tools.translate import _ -import tools.maintenance as tm - -class maintenance_contract_module(osv.osv): - _name ="maintenance.contract.module" - _description = "maintenance contract modules" - _columns = { - 'name' : fields.char('Name', size=128, required=True), - 'version': fields.char('Version', size=64,), - } - -maintenance_contract_module() - -class maintenance_contract(osv.osv): - _name = "maintenance.contract" - _description = "Maintenance Contract" - - def _get_valid_contracts(self, cr, uid): - return [contract for contract in self.browse(cr, uid, self.search(cr, uid, [])) if contract.state == 'valid'] - - def status(self, cr, uid): - covered_modules, uncovered_modules = set(), set() - - status = 'none' - for contract in self._get_valid_contracts(cr, uid): - covered_modules.update([m.name for m in contract.module_ids]) - - if covered_modules: - modobj = self.pool.get('ir.module.module') - modids = modobj.search(cr, uid, [('state', '=', 'installed')]) - uncovered_modules = set(m.name for m in modobj.browse(cr, uid, modids)) - covered_modules - status = ['full', 'partial'][len(uncovered_modules) > 0] - - return { - 'status': status, - 'uncovered_modules': list(uncovered_modules), - } - - def send(self, cr, uid, tb, explanations, remarks=None): - status = self.status(cr, uid) - if status['status'] != 'full': - raise osv.except_osv(_('Error'), _("Your can't submit bug reports due to uncovered modules: %s") % (', '.join(status['uncovered_modules']),)) - - dbmsg = _('This error occurs on database %s') % (cr.dbname,) - if not remarks: - remarks = dbmsg - else: - remarks += '\n\n-----\n' + dbmsg - - valid_contracts = self._get_valid_contracts(cr, uid) - - crm_case_id = None - rc = None - try: - for contract in valid_contracts: - rc = tm.remote_contract(contract.name, contract.password) - if rc.id: - break - rc = None - - if not rc: - raise osv.except_osv(_('Error'), _('Unable to find a valid contract')) - - origin = 'client' - crm_case_id = rc.submit(rc.id, tb, explanations, remarks or '', origin) - - except tm.RemoteContractException, rce: - netsvc.Logger().notifyChannel('maintenance', netsvc.LOG_INFO, rce) - except osv.except_osv: - raise - except: - pass - - cid = rc and rc.name or valid_contracts[0].name - try: - # as backup, put it also in another database... - import urllib - args = urllib.urlencode({ - 'contract_id': cid, - 'crm_case_id': crm_case_id or 0, - 'explanation': explanations, - 'remark': remarks or '', - 'tb': tb, - }) - uo = urllib.urlopen('http://www.openerp.com/scripts/maintenance.php', args) - submit_result = uo.read() - debug(submit_result) - uo.close() - except: - if not crm_case_id: - # TODO schedule a retry (ir.cron) - return False - return True - - def _valid_get(self, cr, uid, ids, field_name, arg, context=None): - res = {} - for contract in self.browse(cr, uid, ids, context=context): - res[contract.id] = ("unvalid", "valid")[contract.date_stop >= time.strftime('%Y-%m-%d')] - return res - - _columns = { - 'name' : fields.char('Contract ID', size=256, required=True, readonly=True), - 'password' : fields.char('Password', size=64, invisible=True, required=True, readonly=True), - 'date_start' : fields.date('Starting Date', readonly=True), - 'date_stop' : fields.date('Ending Date', readonly=True), - 'module_ids' : fields.many2many('maintenance.contract.module', 'maintenance_contract_module_rel', 'contract_id', 'module_id', 'Covered Modules', readonly=True), - 'state' : fields.function(_valid_get, method=True, string="State", type="selection", selection=[('valid', 'Valid'),('unvalid', 'Unvalid')], readonly=True), - 'kind' : fields.selection([('full', 'Full'),('partial', 'Partial')], 'Kind', required=True, readonly=True), - } - _defaults = { - 'password' : lambda obj,cr,uid,context={} : '', - } - _sql_constraints = [ - ('uniq_name', 'unique(name)', "Your maintenance contract is already subscribed in the system !") - ] - -maintenance_contract() - - -class maintenance_contract_wizard(osv.osv_memory): - _name = 'maintenance.contract.wizard' - - _columns = { - 'name' : fields.char('Contract ID', size=256, required=True ), - 'password' : fields.char('Password', size=64, required=True), - 'state' : fields.selection([('draft', 'Draft'),('validated', 'Validated'),('unvalidated', 'Unvalidated')], 'States'), - } - - _defaults = { - 'state' : lambda *a: 'draft', - } - - def action_validate(self, cr, uid, ids, context=None): - if not ids: - return False - - module_proxy = self.pool.get('ir.module.module') - module_ids = module_proxy.search(cr, uid, [('state', '=', 'installed')]) - modules = module_proxy.read(cr, uid, module_ids, ['name', 'installed_version']) - - contract = self.read(cr, uid, ids, ['name', 'password'])[0] - - try: - contract_info = tm.remote_contract(contract['name'], contract['password'], modules) - except tm.RemoteContractException, rce: - raise osv.except_osv(_('Error'), ustr(rce)) - - is_ok = contract_info['status'] in ('partial', 'full') - if is_ok: - module_ids = [] - if contract_info['modules_with_contract']: - for name, version in contract_info['modules_with_contract']: - contract_module = self.pool.get('maintenance.contract.module') - res = contract_module.search(cr, uid, [('name', '=', name),('version', '=', version)]) - if not res: - id = contract_module.create(cr, uid, { 'name' : name, 'version' : version } ) - else: - id = res[0] - module_ids.append(id) - - self.pool.get('maintenance.contract').create( - cr, - uid, { - 'name' : contract['name'], - 'password' : contract['password'], - 'date_start' : contract_info['date_from'], - 'date_stop' : contract_info['date_to'], - 'kind' : contract_info['status'], - 'module_ids' : [(6,0,module_ids)], - } - ) - - return self.write(cr, uid, ids, {'state' : ('unvalidated', 'validated')[is_ok] }, context=context) - -maintenance_contract_wizard() - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/bin/addons/base/maintenance/maintenance_security.xml b/bin/addons/base/maintenance/maintenance_security.xml deleted file mode 100644 index 04b7d6dc2cf..00000000000 --- a/bin/addons/base/maintenance/maintenance_security.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<openerp> -<data noupdate="0"> - -</data> -</openerp> diff --git a/bin/addons/base/maintenance/maintenance_view.xml b/bin/addons/base/maintenance/maintenance_view.xml deleted file mode 100644 index 836344a52df..00000000000 --- a/bin/addons/base/maintenance/maintenance_view.xml +++ /dev/null @@ -1,131 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<openerp> - <data> - - <record id="maintenance_contract_tree_view" model="ir.ui.view"> - <field name="name">maintenance.contract.tree</field> - <field name="model">maintenance.contract</field> - <field name="type">tree</field> - <field name="arch" type="xml"> - <tree string="Maintenance Contract"> - <field name="name"/> - <field name="date_start"/> - <field name="date_stop"/> - <field name="state" /> - </tree> - </field> - </record> - - <record id="maintenance_contract_form_view" model="ir.ui.view"> - <field name="name">maintenance.contract.form</field> - <field name="model">maintenance.contract</field> - <field name="type">form</field> - <field name="arch" type="xml"> - <form string="Maintenance Contract"> - <group col="6" colspan="4"> - <field name="name"/> - <field name="date_start"/> - <field name="date_stop"/> - </group> - <separator string="Covered Modules" colspan="4"/> - <field name="module_ids" nolabel="1" colspan="4"> - <tree string="Covered Modules"> - <field name="name" /> - <field name="version" /> - </tree> - </field> - <field name="state" colspan="4"/> - </form> - </field> - </record> - - <record id="maintenance_contract_search_view" model="ir.ui.view"> - <field name="name">maintenance.contract.search</field> - <field name="model">maintenance.contract</field> - <field name="type">search</field> - <field name="arch" type="xml"> - <search string="Maintenance Contract"> - <field name="name"/> - <field name="date_start"/> - <field name="date_stop"/> - </search> - </field> - </record> - - <record id="maintenance_contract_view_calendar" model="ir.ui.view"> - <field name="name">maintenance.contract.calendar</field> - <field name="model">maintenance.contract</field> - <field name="type">calendar</field> - <field name="arch" type="xml"> - <calendar string="Maintenance Contract" date_start="date_start" color="state"> - <field name="name"/> - <field name="state"/> - </calendar> - </field> - </record> - - <record id="action_maintenance_contract_form" model="ir.actions.act_window"> - <field name="name">Maintenance Contracts</field> - <field name="type">ir.actions.act_window</field> - <field name="res_model">maintenance.contract</field> - <field name="view_type">form</field> - <field name="view_mode">tree,form,calendar</field> - <field name="search_view_id" ref="maintenance_contract_search_view"/> - </record> - - <menuitem - name="Maintenance" - id="maintenance" - parent="base.menu_administration" groups="base.group_extended"/> - - <menuitem - action="action_maintenance_contract_form" - id="menu_maintenance_contract" - parent="maintenance"/> - - <record id="maintenance_contract_add_wizard" model="ir.ui.view"> - <field name="name">maintenance.contract.add.wizard</field> - <field name="model">maintenance.contract.wizard</field> - <field name="type">form</field> - <field name="arch" type="xml"> - <form string="Add Maintenance Contract" col="2"> - <group col="1"> - <separator string="Add Maintenance Contract" /> - <group states="draft"> - <field name="name" width="250" /> - <newline /> - <field name="password" password="True" /> - <field name="state" invisible="1" /> - </group> - <group states="validated"> - <label string="Maintenance contract added !"/> - </group> - <group states="unvalidated"> - <label string="Could you check your contract information ?" /> - </group> - </group> - <group colspan="4"> - <button type="object" string="_Cancel" icon="gtk-cancel" special="cancel" states="draft"/> - <button type="object" string="_Validate" icon="gtk-apply" name="action_validate" states="draft"/> - <button type="object" string="_Close" icon="gtk-close" special="cancel" states="validated,unvalidated"/> - </group> - </form> - </field> - </record> - - <record id="action_maintenance_contract_add_wizard" model="ir.actions.act_window"> - <field name="name">Add Maintenance Contract</field> - <field name="type">ir.actions.act_window</field> - <field name="res_model">maintenance.contract.wizard</field> - <field name="view_type">form</field> - <field name="view_mode">form</field> - <field name="target">new</field> - </record> - - <menuitem - action="action_maintenance_contract_add_wizard" - id="menu_maintenance_contract_add" - parent="maintenance" /> - - </data> -</openerp> diff --git a/bin/addons/base/maintenance/__init__.py b/bin/addons/base/publisher_warranty/__init__.py index 329c61301d9..6b60ddf3ca1 100644 --- a/bin/addons/base/maintenance/__init__.py +++ b/bin/addons/base/publisher_warranty/__init__.py @@ -19,7 +19,7 @@ # ############################################################################## -import maintenance +import publisher_warranty # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/bin/addons/base/publisher_warranty/publisher_warranty.py b/bin/addons/base/publisher_warranty/publisher_warranty.py new file mode 100644 index 00000000000..34c2329b227 --- /dev/null +++ b/bin/addons/base/publisher_warranty/publisher_warranty.py @@ -0,0 +1,323 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 OpenERP S.A. (<http://www.openerp.com>). +# +# This program is free software: you can redistribute it and/or modify +# 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. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################## +""" +Module to handle publisher warranty contracts as well as notifications from +OpenERP. +""" + +import datetime +import logging +import sys +import urllib +import urllib2 + +import pooler +import release +from osv import osv, fields +from tools.translate import _ +from tools.safe_eval import safe_eval +from tools.config import config +from tools import misc + +_logger = logging.getLogger(__name__) + +""" +Time interval that will be used to determine up to which date we will +check the logs to see if a message we just received was already logged. +@type: datetime.timedelta +""" +_PREVIOUS_LOG_CHECK = datetime.timedelta(days=365) + +class publisher_warranty_contract(osv.osv): + """ + Osv representing a publisher warranty contract. + """ + _name = "publisher_warranty.contract" + + def _get_valid_contracts(self, cr, uid): + """ + Return the list of the valid contracts encoded in the system. + + @return: A list of contracts + @rtype: list of publisher_warranty.contract browse records + """ + return [contract for contract in self.browse(cr, uid, self.search(cr, uid, [])) + if contract.state == 'valid'] + + def status(self, cr, uid): + """ Method called by the client to check availability of publisher warranty contract. """ + + contracts = self._get_valid_contracts(cr, uid) + return { + 'status': "full" if contracts else "none" , + 'uncovered_modules': list(), + } + + def send(self, cr, uid, tb, explanations, remarks=None): + """ Method called by the client to send a problem to the publisher warranty server. """ + + if not remarks: + remarks = "" + + valid_contracts = self._get_valid_contracts(cr, uid) + valid_contract = valid_contracts[0] + + try: + origin = 'client' + dbuuid = self.pool.get('ir.config_parameter').get_param(cr, uid, 'database.uuid') + db_create_date = self.pool.get('ir.config_parameter').get_param(cr, uid, 'database.create_date') + + msg = {'contract_name': valid_contract.name, + 'tb': tb, + 'explanations': explanations, + 'remarks': remarks, + 'origin': origin, + 'dbname': cr.dbname, + 'dbuuid': dbuuid, + 'db_create_date': db_create_date} + + + add_arg = {"timeout":30} if sys.version_info >= (2,6) else {} + uo = urllib2.urlopen(config.get("publisher_warranty_url"), + urllib.urlencode({'arg0': msg, "action": "send",}),**add_arg) + try: + submit_result = uo.read() + finally: + uo.close() + + result = safe_eval(submit_result) + + crm_case_id = result + + if not crm_case_id: + return False + + except osv.except_osv: + raise + except Exception: + _logger.warning("Error sending problem report", exc_info=1) + raise osv.except_osv("Connection error", "An error occured during the connection " + + "with the publisher warranty server.") + + return True + + def check_validity(self, cr, uid, ids, context=None): + """ + Check the validity of a publisher warranty contract. This method just call get_logs() but checks + some more things, so it can be called from a user interface. + """ + contract_id = ids[0] + contract = self.browse(cr, uid, contract_id) + state = contract.state + validated = state != "unvalidated" + + self.get_logs(cr, uid, ids, cron_mode=False, context=context) + + contract = self.browse(cr, uid, contract_id) + validated2 = contract.state != "unvalidated" + if not validated and not validated2: + raise osv.except_osv(_("Contract validation error"), + _("Please check your publisher warranty contract name and validity.")) + + def get_logs(self, cr, uid, ids, cron_mode=True, context=None): + """ + Send a message to OpenERP's publisher warranty server to check the validity of + the contracts, get notifications, etc... + + @param cron_mode: If true, catch all exceptions (appropriate for usage in a cron). + @type cron_mode: boolean + """ + try: + try: + result = get_sys_logs(cr, uid) + except Exception: + if cron_mode: # we don't want to see any stack trace in cron + return False + _logger.debug("Exception while sending a get logs messages", exc_info=1) + raise osv.except_osv(_("Error"), _("Error during communication with the publisher warranty server.")) + + contracts = result["contracts"] + for contract in contracts: + c_id = self.search(cr, uid, [("name","=",contract)])[0] + date_from = contracts[contract][0] + date_to = contracts[contract][1] + state = contracts[contract][2] + self.write(cr, uid, c_id, { + "date_start": date_from, + "date_stop": date_to, + "state": state, + }) + + limit_date = (datetime.datetime.now() - _PREVIOUS_LOG_CHECK).strftime(misc.DEFAULT_SERVER_DATETIME_FORMAT) + for message in result["messages"]: + ids = self.pool.get("res.log").search(cr, uid, [("res_model", "=", "publisher_warranty.contract"), + ("create_date", ">=", limit_date), + ("name", "=", message)]) + if ids: + continue + self.pool.get('res.log').create(cr, uid, + { + 'name': message, + 'res_model': "publisher_warranty.contract", + "read": True, + "user_id": False, + }, + context=context + ) + except Exception: + if cron_mode: + return False # we don't want to see any stack trace in cron + else: + raise + return True + + def get_last_user_messages(self, cr, uid, limit, context=None): + """ + Get the messages to be written in the web client. + @return: A list of html messages with ids, can be False or empty. + @rtype: list of tuples(int,string) + """ + ids = self.pool.get('res.log').search(cr, uid, [("res_model", "=", "publisher_warranty.contract")] + , order="create_date desc", limit=limit) + if not ids: + return [] + messages = [(x.id, x.name) for x in self.pool.get('res.log').browse(cr, uid, ids)] + + return messages + + def del_user_message(self, cr, uid, id, context=None): + """ + Delete a message. + """ + self.pool.get('res.log').unlink(cr, uid, [id]) + + return True + + _columns = { + 'name' : fields.char('Serial Key', size=384, required=True), + 'date_start' : fields.date('Starting Date', readonly=True), + 'date_stop' : fields.date('Ending Date', readonly=True), + 'state' : fields.selection([('unvalidated', 'Unvalidated'), ('valid', 'Valid') + , ('terminated', 'Terminated'), ('canceled', 'Canceled')], string="State", readonly=True), + 'kind' : fields.char('Kind', size=64, readonly=True), + } + + _defaults = { + 'state': 'unvalidated', + } + + _sql_constraints = [ + ('uniq_name', 'unique(name)', "Your publisher warranty contract is already subscribed in the system !") + ] + +publisher_warranty_contract() + +class maintenance_contract(osv.osv_memory): + """ Old osv we only keep for compatibility with the clients. """ + + _name = "maintenance.contract" + + def status(self, cr, uid): + return self.pool.get("publisher_warranty.contract").status(cr, uid) + + def send(self, cr, uid, tb, explanations, remarks=None): + return self.pool.get("publisher_warranty.contract").send(cr, uid, tb, explanations, remarks) + +maintenance_contract() + +class publisher_warranty_contract_wizard(osv.osv_memory): + """ + A wizard osv to help people entering a publisher warranty contract. + """ + _name = 'publisher_warranty.contract.wizard' + _inherit = "ir.wizard.screen" + + _columns = { + 'name' : fields.char('Serial Key', size=256, required=True ), + 'state' : fields.selection([("draft", "Draft"), ("finished", "Finished")]) + } + + _defaults = { + "state": "draft", + } + + def action_validate(self, cr, uid, ids, context=None): + if not ids: + return False + + wiz = self.browse(cr, uid, ids[0]) + c_name = wiz.name + + contract_osv = self.pool.get("publisher_warranty.contract") + contracts = contract_osv.search(cr, uid, [("name","=",c_name)]) + if contracts: + raise osv.except_osv(_("Error"), _("That contract is already registered in the system.")) + + contract_id = contract_osv.create(cr, uid, { + "name": c_name, + "state": "unvalidated", + }) + + contract_osv.check_validity(cr, uid, [contract_id]) + + self.write(cr, uid, ids, {"state": "finished"}) + + return True + + +publisher_warranty_contract_wizard() + +def get_sys_logs(cr, uid): + """ + Utility method to send a publisher warranty get logs messages. + """ + pool = pooler.get_pool(cr.dbname) + + dbuuid = pool.get('ir.config_parameter').get_param(cr, uid, 'database.uuid') + db_create_date = pool.get('ir.config_parameter').get_param(cr, uid, 'database.create_date') + nbr_users = pool.get("res.users").search(cr, uid, [], count=True) + contractosv = pool.get('publisher_warranty.contract') + contracts = contractosv.browse(cr, uid, contractosv.search(cr, uid, [])) + user = pool.get("res.users").browse(cr, uid, uid) + msg = { + "dbuuid": dbuuid, + "nbr_users": nbr_users, + "dbname": cr.dbname, + "db_create_date": db_create_date, + "version": release.version, + "contracts": [c.name for c in contracts], + "language": user.context_lang, + } + + add_arg = {"timeout":30} if sys.version_info >= (2,6) else {} + uo = urllib2.urlopen(config.get("publisher_warranty_url"), + urllib.urlencode({'arg0': msg, "action": "update",}), **add_arg) + try: + submit_result = uo.read() + finally: + uo.close() + + result = safe_eval(submit_result) + + return result + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/bin/addons/base/publisher_warranty/publisher_warranty_data.xml b/bin/addons/base/publisher_warranty/publisher_warranty_data.xml new file mode 100644 index 00000000000..68594e5d88f --- /dev/null +++ b/bin/addons/base/publisher_warranty/publisher_warranty_data.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<openerp> + <data> + + <record id="ir_cron_ping_scheduler" model="ir.cron"> + <field name="name">Update System Logs</field> + <field eval="True" name="active" /> + <field name="user_id" ref="base.user_root" /> + <field name="interval_number">1</field> + <field name="interval_type">weeks</field> + <field name="numbercall">-1</field> + <field eval="False" name="doall" /> + <field eval="'publisher_warranty.contract'" name="model" /> + <field eval="'get_logs'" name="function" /> + <field eval="'(None,)'" name="args" /> + <field name="priority">1000</field> + </record> + + </data> +</openerp>
\ No newline at end of file diff --git a/bin/addons/base/publisher_warranty/publisher_warranty_view.xml b/bin/addons/base/publisher_warranty/publisher_warranty_view.xml new file mode 100644 index 00000000000..2eb03715537 --- /dev/null +++ b/bin/addons/base/publisher_warranty/publisher_warranty_view.xml @@ -0,0 +1,146 @@ +<?xml version="1.0" encoding="utf-8"?> +<openerp> + <data> + + <record id="publisher_warranty_contract_tree_view" model="ir.ui.view"> + <field name="name">publisher_warranty.contract.tree</field> + <field name="model">publisher_warranty.contract</field> + <field name="type">tree</field> + <field name="arch" type="xml"> + <tree string="Publisher Warranty Contracts"> + <field name="name"/> + <field name="date_start"/> + <field name="date_stop"/> + <field name="state" /> + </tree> + </field> + </record> + + <record id="publisher_warranty_contract_form_view" model="ir.ui.view"> + <field name="name">publisher_warranty.contract.form</field> + <field name="model">publisher_warranty.contract</field> + <field name="type">form</field> + <field name="arch" type="xml"> + <form string="Publisher Warranty Contract"> + <group col="2" colspan="4"> + <group col="2"> + <field name="name"/> + </group> + <group col="2"> + <field name="date_start"/> + <field name="date_stop"/> + </group> + <group col="2"> + <field name="state"/> + <field name="kind"/> + </group> + <group col="2"> + <button name="check_validity" string="Validate" type="object" + attrs="{'invisible':[('state','in',['valid', 'terminated', 'canceled'])]}"/> + <button name="check_validity" string="Refresh Validation Dates" type="object" + attrs="{'invisible':[('state','in',['unvalidated'])]}"/> + </group> + </group> + </form> + </field> + </record> + + <record id="publisher_warranty_contract_search_view" model="ir.ui.view"> + <field name="name">publisher_warranty.contract.search</field> + <field name="model">publisher_warranty.contract</field> + <field name="type">search</field> + <field name="arch" type="xml"> + <search string="Publisher Warranty Contract"> + <field name="name"/> + <field name="date_start"/> + <field name="date_stop"/> + </search> + </field> + </record> + + <record id="publisher_warranty_contract_view_calendar" model="ir.ui.view"> + <field name="name">publisher_warranty.contract.calendar</field> + <field name="model">publisher_warranty.contract</field> + <field name="type">calendar</field> + <field name="arch" type="xml"> + <calendar string="Maintenance Contract" date_start="date_start" color="state"> + <field name="name"/> + <field name="state"/> + </calendar> + </field> + </record> + + <record id="action_publisher_warranty_contract_form" model="ir.actions.act_window"> + <field name="name">Contracts</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">publisher_warranty.contract</field> + <field name="view_type">form</field> + <field name="view_mode">tree,form,calendar</field> + <field name="search_view_id" ref="publisher_warranty_contract_search_view"/> + </record> + + <menuitem name="Publisher Warranty" id="publisher_warranty" + parent="base.menu_administration" groups="base.group_extended"/> + + <menuitem action="action_publisher_warranty_contract_form" id="menu_publisher_warranty_contract" + parent="publisher_warranty" sequence="2"/> + + + <record id="publisher_warranty_contract_add_wizard" model="ir.ui.view"> + <field name="name">publisher_warranty.contract.add.wizard</field> + <field name="model">publisher_warranty.contract.wizard</field> + <field name="type">form</field> + <field name="arch" type="xml"> + <form string="Register a Contract"> + <group col="8"> + <group colspan="3" col="1"> + <field name="config_logo" widget="image" width="220" height="130" nolabel="1" colspan="1"/> + <newline/> + <label width="220" string="This wizard helps you register a publisher warranty contract in your OpenERP system. After the contract has been registered, you will be able to send issues directly to OpenERP."/> + <label width="220"/> + <label width="220" string=""/> + <field name="state" invisible="1"/> + </group> + <separator orientation="vertical" rowspan="5"/> + <group colspan="4"> + <separator string="Register a Contract" colspan="4"/> + <group states="draft" col="4"> + <label string="Please enter the serial key provided in your contract document:" colspan="4"/> + <field name="name" colspan="4"/> + </group> + <group states="finished" col="4"> + <label string="Publisher warranty contract successfully registered!" colspan="4"/> + </group> + </group> + <group colspan="8" col="8" states="draft"> + <separator string="" colspan="8"/> + <label colspan="6" width="220"/> + <button special="cancel" string="Cancel" icon="gtk-cancel"/> + <button name="action_validate" string="Register" type="object" icon="gtk-apply"/> + </group> + <group colspan="8" col="8" states="finished"> + <separator string="" colspan="8"/> + <label colspan="6" width="220"/> + <button special="cancel" string="Close" icon="gtk-ok"/> + </group> + </group> + </form> + </field> + </record> + + <record id="action_publisher_warranty_contract_add_wizard" model="ir.actions.act_window"> + <field name="name">Register a Contract</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">publisher_warranty.contract.wizard</field> + <field name="view_type">form</field> + <field name="view_mode">form</field> + <field name="target">new</field> + </record> + + <menuitem + action="action_publisher_warranty_contract_add_wizard" + id="menu_publisher_warranty_contract_add" + parent="publisher_warranty" sequence="1"/> + + </data> +</openerp> diff --git a/bin/addons/base/res/res_log.py b/bin/addons/base/res/res_log.py index 0862a686aa8..26e1eaeed69 100644 --- a/bin/addons/base/res/res_log.py +++ b/bin/addons/base/res/res_log.py @@ -20,24 +20,23 @@ ############################################################################## from osv import fields, osv -import tools class res_log(osv.osv): _name = 'res.log' _columns = { - 'name': fields.char('Message', size=128, help='The logging message.', required=True), - 'user_id': fields.many2one('res.users','User', required=True), - 'res_model': fields.char('Object', size=128), + 'name': fields.char('Message', size=250, help='The logging message.', required=True, select=1), + 'user_id': fields.many2one('res.users','User'), + 'res_model': fields.char('Object', size=128, select=1), 'context': fields.char('Context', size=250), 'res_id': fields.integer('Object ID'), 'secondary': fields.boolean('Secondary Log', help='Do not display this log if it belongs to the same object the user is working on'), - 'create_date': fields.datetime('Created Date', readonly=True), - 'read': fields.boolean('Read', help="If this log item has been read, get() should not send it to the client") + 'create_date': fields.datetime('Creation Date', readonly=True, select=1), + 'read': fields.boolean('Read', help="If this log item has been read, get() should not send it to the client"), } _defaults = { 'user_id': lambda self,cr,uid,ctx: uid, 'context': "{}", - 'read': False + 'read': False, } _order='create_date desc' diff --git a/bin/addons/base/res/res_log_view.xml b/bin/addons/base/res/res_log_view.xml index 4fc137eb26b..86d1e0d06cb 100644 --- a/bin/addons/base/res/res_log_view.xml +++ b/bin/addons/base/res/res_log_view.xml @@ -11,6 +11,8 @@ <filter icon="terp-stock_align_left_24" string="Unread" domain="[('read','<>',True)]" name="unread"/> <separator orientation="vertical"/> <filter icon="terp-stock_align_left_24" string="My Logs" domain="[('user_id','=',uid)]" name="my"/> + <filter icon="terp-stock_align_left_24" string="System Logs" + domain="[('res_model','=','publisher_warranty.contract')]" name="sys"/> <separator orientation="vertical"/> <field name="name"/> <field name="user_id"/> diff --git a/bin/addons/base/security/ir.model.access.csv b/bin/addons/base/security/ir.model.access.csv index 62eb8ffe2b1..b83d858d4e8 100644 --- a/bin/addons/base/security/ir.model.access.csv +++ b/bin/addons/base/security/ir.model.access.csv @@ -112,8 +112,8 @@ "access_res_payterm_group_system","res_payterm_group_system","model_res_payterm","group_system",1,1,1,1 "access_res_bank_group_partner_manager","res_bank_group_partner_manager","model_res_bank","group_partner_manager",1,1,1,1 "access_res_bank_user","res_bank user","model_res_bank","group_user",1,0,0,0 -"access_maintenance_group_user","maintenance_contract group_user","model_maintenance_contract","group_system",1,1,1,1 -"access_maintenance_contract_module","maintenance.contract.module","model_maintenance_contract_module","group_system",1,1,1,1 +"access_publisher_warranty_group_user","publisher_warranty_contract group_user","model_publisher_warranty_contract","group_system",1,1,1,1 +"access_publisher_warranty_all","publisher_warranty_contract all","model_publisher_warranty_contract",,1,0,0,0 "access_multi_company_default user","multi_company_default all","model_multi_company_default",,1,0,0,0 "access_multi_company_default manager","multi_company_default Manager","model_multi_company_default","group_erp_manager",1,1,1,1 "access_ir_filter all","ir_filters all","model_ir_filters",,1,0,0,0 @@ -123,3 +123,4 @@ "access_res_widget","res.widget","model_res_widget","group_erp_manager",1,1,1,1 "access_res_widget_user","res.widget.user","model_res_widget",,1,0,0,0 "access_res_log_all","res.log","model_res_log",,1,1,1,1 +"access_ir_config_parameter","ir_config_parameter","model_ir_config_parameter",,1,0,0,0 diff --git a/bin/tools/config.py b/bin/tools/config.py index f98cdbab1b9..0fe2664c2a9 100644 --- a/bin/tools/config.py +++ b/bin/tools/config.py @@ -31,8 +31,8 @@ def check_ssl(): try: from OpenSSL import SSL import socket - - return hasattr(socket, 'ssl') + + return hasattr(socket, 'ssl') and hasattr(SSL, "Connection") except: return False @@ -91,7 +91,10 @@ class configmanager(object): 'static_http_url_prefix': None, 'secure_cert_file': 'server.cert', 'secure_pkey_file': 'server.pkey', + 'publisher_warranty_url': 'http://services.openerp.com/publisher-warranty', } + + self.blacklist_for_save = set(["publisher_warranty_url"]) self.misc = {} self.config_file = fname @@ -224,7 +227,7 @@ class configmanager(object): parser.add_option_group(security) def parse_config(self): - (opt, args) = self.parser.parse_args() + opt = self.parser.parse_args()[0] def die(cond, msg): if cond: @@ -317,7 +320,7 @@ class configmanager(object): # If an explicit TZ was provided in the config, make sure it is known try: import pytz - tz = pytz.timezone(self.options['timezone']) + pytz.timezone(self.options['timezone']) except pytz.UnknownTimeZoneError: die(True, "The specified timezone (%s) is invalid" % self.options['timezone']) except: @@ -374,7 +377,10 @@ class configmanager(object): fp.close() if is_win32: - import _winreg + try: + import _winreg + except ImportError: + _winreg = None x=_winreg.ConnectRegistry(None,_winreg.HKEY_LOCAL_MACHINE) y = _winreg.OpenKey(x, r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", 0,_winreg.KEY_ALL_ACCESS) _winreg.SetValueEx(y,"PGPASSFILE", 0, _winreg.REG_EXPAND_SZ, filename ) @@ -436,16 +442,18 @@ class configmanager(object): p = ConfigParser.ConfigParser() loglevelnames = dict(zip(self._LOGLEVELS.values(), self._LOGLEVELS.keys())) p.add_section('options') - for opt in self.options.keys(): + for opt in sorted(self.options.keys()): if opt in ('version', 'language', 'translate_out', 'translate_in', 'init', 'update'): continue + if opt in self.blacklist_for_save: + continue if opt in ('log_level', 'assert_exit_level'): p.set('options', opt, loglevelnames.get(self.options[opt], self.options[opt])) else: p.set('options', opt, self.options[opt]) - for sec in self.misc.keys(): - for opt in self.misc[sec].keys(): + for sec in sorted(self.misc.keys()): + for opt in sorted(self.misc[sec].keys()): p.set(sec,opt,self.misc[sec][opt]) # try to create the directories and write the file diff --git a/bin/tools/maintenance.py b/bin/tools/maintenance.py deleted file mode 100644 index 83cf5e3b8bd..00000000000 --- a/bin/tools/maintenance.py +++ /dev/null @@ -1,69 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). -# -# This program is free software: you can redistribute it and/or modify -# 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. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -############################################################################## - -import xmlrpclib - -class RemoteContractException(Exception): pass - -class remote_contract(object): - def __init__(self, contract_id, contract_password, modules=None): - self.__server = 'http://tiny.my.odoo.com:8069/xmlrpc/' - self.__db = "tiny_belgium" - self.__password = "maintenance" - self.__login = "maintenance" - - rpc = xmlrpclib.ServerProxy(self.__server + 'common') - try: - self.__userid = rpc.login(self.__db, self.__login, self.__password) - except: - raise RemoteContractException("Unable to contact the migration server") - - if not self.__userid: - raise RemoteContractException("Unable to contact the migration server") - - self.__rpc = xmlrpclib.ServerProxy(self.__server + 'object') - - - contract = { - 'name': contract_id, - 'password': contract_password, - } - if modules is None: - modules = [] - - info = self.check_contract(modules, contract) - for n in info: - setattr(self, n, info[n]) - - self.name = contract_id - self.contract_id = self.name - self.password = contract_password - - def __getattr__(self, fun): - def remote_call(*args, **kwargs): - return self.__rpc.execute(self.__db, self.__userid, self.__password, 'maintenance.maintenance', fun, *args, **kwargs) - return remote_call - - def __getitem__(self, item): - return getattr(self, item) - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - |
