diff --git a/CHANGELOG b/CHANGELOG index 18f8c97802..688fdf9039 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Remove request + Version 2.8.0 - 2013-04-22 * Bug fixes (see mercurial logs for details) * Allow to search on target of Reference field diff --git a/etc/trytond.conf b/etc/trytond.conf index aea2683979..6208dd5e33 100644 --- a/etc/trytond.conf +++ b/etc/trytond.conf @@ -58,6 +58,7 @@ jsonrpc = localhost:8000 #smtp_tls = False #smtp_password = False #smtp_user = False +#smtp_default_from_email = False # Configure the path to store attachments and sqlite database #data_path = /var/lib/trytond diff --git a/trytond/config.py b/trytond/config.py index 4f4d5a6980..58c27ee484 100644 --- a/trytond/config.py +++ b/trytond/config.py @@ -12,6 +12,8 @@ except ImportError: import os import ConfigParser import time +import getpass +import socket def get_hostname(netloc): @@ -69,6 +71,8 @@ class ConfigManager(object): 'smtp_tls': False, 'smtp_user': False, 'smtp_password': False, + 'smtp_default_from_email': '%s@%s' % ( + getpass.getuser(), socket.getfqdn()), 'data_path': '/var/lib/trytond', 'multi_server': False, 'session_timeout': 600, diff --git a/trytond/ir/cron.py b/trytond/ir/cron.py index 320b9c1d1e..48b2004b0f 100644 --- a/trytond/ir/cron.py +++ b/trytond/ir/cron.py @@ -6,12 +6,14 @@ from dateutil.relativedelta import relativedelta import traceback import sys import logging +from email.mime.text import MIMEText from ..model import ModelView, ModelSQL, fields -from ..tools import safe_eval +from ..tools import safe_eval, get_smtp_server from ..transaction import Transaction from ..pool import Pool from ..backend import TableHandler +from ..config import CONFIG __all__ = [ 'Cron', @@ -60,10 +62,10 @@ class Cron(ModelSQL, ModelView): def __setup__(cls): super(Cron, cls).__setup__() cls._error_messages.update({ - 'request_title': 'Scheduled action failed', - 'request_body': "The following action failed to execute " - "properly: \"%s\"\n Traceback: \n\n%s\n" - }) + 'request_title': 'Scheduled action failed', + 'request_body': ("The following action failed to execute " + "properly: \"%s\"\n%s\n Traceback: \n\n%s\n") + }) @classmethod def __register__(cls, module_name): @@ -120,29 +122,33 @@ class Cron(ModelSQL, ModelView): return _INTERVALTYPES[cron.interval_type](cron.interval_number) @classmethod - def _get_request_values(cls, cron): + def send_error_message(cls, cron): tb_s = ''.join(traceback.format_exception(*sys.exc_info())) tb_s = tb_s.decode('utf-8', 'ignore') - name = cls.raise_user_error('request_title', + subject = cls.raise_user_error('request_title', raise_exception=False) - body = cls.raise_user_error('request_body', (cron.name, tb_s), + body = cls.raise_user_error('request_body', + (cron.name, cron.__url__, tb_s), raise_exception=False) - values = { - 'name': name, - 'priority': '2', - 'act_from': cron.user.id, - 'act_to': cron.request_user.id, - 'body': body, - 'date_sent': datetime.datetime.now(), - 'references': [ - ('create', [{ - 'reference': '%s,%s' % (cls.__name__, cron.id), - }]), - ], - 'state': 'waiting', - 'trigger_date': datetime.datetime.now(), - } - return values + + from_addr = CONFIG['smtp_default_from_email'] + to_addr = cron.request_user.email + + msg = MIMEText(body) + msg['To'] = to_addr + msg['From'] = from_addr + msg['Subject'] = subject + logger = logging.getLogger(__name__) + if not to_addr: + logger.error(msg.as_string()) + else: + try: + server = get_smtp_server() + server.sendmail(from_addr, to_addr, msg.as_string()) + server.quit() + except Exception, exception: + logger.error('Unable to deliver email (%s):\n %s' + % (exception, msg.as_string())) @classmethod def _callback(cls, cron): @@ -156,15 +162,12 @@ class Cron(ModelSQL, ModelView): except Exception: Transaction().cursor.rollback() - Request = pool.get('res.request') req_user = cron.request_user language = (req_user.language.code if req_user.language else Config.get_language()) with contextlib.nested(Transaction().set_user(cron.user.id), Transaction().set_context(language=language)): - values = cls._get_request_values(cron) - Request.create([values]) - Transaction().cursor.commit() + cls.send_error_message(cron) @classmethod def run(cls, db_name): diff --git a/trytond/protocols/dispatcher.py b/trytond/protocols/dispatcher.py index e00f0b0069..899146a7fa 100644 --- a/trytond/protocols/dispatcher.py +++ b/trytond/protocols/dispatcher.py @@ -183,17 +183,16 @@ def dispatch(host, port, protocol, database_name, user, session, object_type, database_name) + tb_s) transaction.cursor.rollback() raise - if not (object_name == 'res.request' and method == 'request_get'): - with Transaction().start(database_name, 0) as transaction: - pool = Pool(database_name) - Session = pool.get('ir.session') - try: - Session.reset(session) - except DatabaseOperationalError: - # Silently fail when reseting session - transaction.cursor.rollback() - else: - transaction.cursor.commit() + with Transaction().start(database_name, 0) as transaction: + pool = Pool(database_name) + Session = pool.get('ir.session') + try: + Session.reset(session) + except DatabaseOperationalError: + # Silently fail when reseting session + transaction.cursor.rollback() + else: + transaction.cursor.commit() Cache.resets(database_name) return result diff --git a/trytond/res/__init__.py b/trytond/res/__init__.py index 396cd3a9a4..481f45ab49 100644 --- a/trytond/res/__init__.py +++ b/trytond/res/__init__.py @@ -3,7 +3,6 @@ from ..pool import Pool from .group import * from .user import * -from .request import * from .ir import * @@ -17,10 +16,6 @@ def register(): UserGroup, Warning_, UserConfigStart, - Request, - RequestLink, - RequestHistory, - RequestReference, UIMenuGroup, ActionGroup, ModelFieldGroup, diff --git a/trytond/res/ir.xml b/trytond/res/ir.xml index dd99cc253a..9c52d980b4 100644 --- a/trytond/res/ir.xml +++ b/trytond/res/ir.xml @@ -746,11 +746,6 @@ this repository contains the full copyright notices and license terms. --> - - Scheduler - ir.cron - - ir.sequence.type diff --git a/trytond/res/request.py b/trytond/res/request.py deleted file mode 100644 index 4151b504fd..0000000000 --- a/trytond/res/request.py +++ /dev/null @@ -1,266 +0,0 @@ -#This file is part of Tryton. The COPYRIGHT file at the top level of -#this repository contains the full copyright notices and license terms. -import datetime -from ..model import ModelView, ModelSQL, fields -from ..pyson import Eval, If -from ..transaction import Transaction -from ..pool import Pool -from ..rpc import RPC - -__all__ = [ - 'Request', 'RequestLink', 'RequestHistory', 'RequestReference', - ] - -_STATES = [ - ('draft', 'Draft'), - ('waiting', 'Waiting'), - ('chatting', 'Chatting'), - ('closed', 'Closed'), -] - -_PRIORITIES = [ - ('0', 'Low'), - ('1', 'Normal'), - ('2', 'High'), -] - -_READONLY = If(Eval('state').in_(['waiting', 'closed']), - True, - If(Eval('state') == 'chatting', - Eval('act_from') != Eval('_user'), - False)) -_DEPENDS = ['state', 'act_from'] - - -class Request(ModelSQL, ModelView): - "Request" - __name__ = 'res.request' - name = fields.Char('Subject', states={ - 'readonly': _READONLY, - }, required=True, depends=_DEPENDS) - active = fields.Boolean('Active') - priority = fields.Selection(_PRIORITIES, 'Priority', states={ - 'readonly': _READONLY, - }, required=True, order_field='priority', depends=_DEPENDS) - act_from = fields.Many2One('res.user', 'From', required=True, - readonly=True) - act_to = fields.Many2One('res.user', 'To', required=True, - domain=[('active', '=', True)], - states={ - 'readonly': _READONLY, - }, depends=_DEPENDS) - body = fields.Text('Body', states={ - 'readonly': _READONLY, - }, depends=_DEPENDS) - date_sent = fields.DateTime('Date', readonly=True) - trigger_date = fields.DateTime('Trigger Date', states={ - 'readonly': _READONLY, - }, depends=_DEPENDS) - references = fields.One2Many('res.request.reference', 'request', - 'References', states={ - 'readonly': If(Eval('state') == 'closed', - True, - Eval('act_from', 0) != Eval('_user', 0)), - }, depends=['state', 'act_from']) - number_references = fields.Function(fields.Integer('Number of References', - on_change_with=['references']), 'on_change_with_number_references') - state = fields.Selection(_STATES, 'State', required=True, readonly=True) - history = fields.One2Many('res.request.history', 'request', - 'History', readonly=True) - - @classmethod - def __setup__(cls): - super(Request, cls).__setup__() - cls.__rpc__.update({ - 'request_get': RPC(), - }) - cls._order.insert(0, ('priority', 'DESC')) - cls._order.insert(1, ('trigger_date', 'DESC')) - cls._order.insert(2, ('create_date', 'DESC')) - cls._buttons.update({ - 'send': { - 'invisible': ~Eval('state').in_(['draft', 'chatting']), - 'readonly': Eval('act_from') != Eval('_user'), - }, - 'reply': { - 'invisible': Eval('state') != 'waiting', - 'readonly': Eval('act_to') != Eval('_user'), - }, - 'close': { - 'invisible': ~Eval('state').in_(['waiting', 'draft', - 'chatting']), - }, - }) - - @staticmethod - def default_act_from(): - return int(Transaction().user) - - @staticmethod - def default_state(): - return 'draft' - - @staticmethod - def default_active(): - return True - - @staticmethod - def default_priority(): - return '1' - - def on_change_with_number_references(self, name=None): - return len(self.references or '') - - @classmethod - @ModelView.button - def send(cls, requests): - pool = Pool() - RequestHistory = pool.get('res.request.history') - to_create = [] - for request in requests: - values = { - 'request': request.id, - 'act_from': request.act_from.id, - 'act_to': request.act_to.id, - 'body': request.body, - 'state': request.state, - 'subject': request.name, - 'number_references': request.number_references, - 'priority': request.priority, - } - if values['body'] and len(values['body']) > 128: - values['name'] = values['body'][:125] + '...' - else: - values['name'] = values['body'] or '/' - to_create.append(values) - if to_create: - RequestHistory.create(to_create) - cls.write(requests, { - 'state': 'waiting', - 'date_sent': datetime.datetime.now(), - }) - - @classmethod - @ModelView.button - def reply(cls, requests): - user = Transaction().user - for request in requests: - cls.write([request], { - 'state': 'chatting', - 'act_from': user, - 'act_to': request.act_from.id, - 'trigger_date': None, - 'body': '', - }) - - @classmethod - @ModelView.button - def close(cls, requests): - cls.write(requests, {'state': 'closed', 'active': False}) - - @classmethod - def request_get(cls): - user = Transaction().user - requests = cls.search([ - ('act_to', '=', user), - ['OR', - ('trigger_date', '<=', datetime.datetime.now()), - ('trigger_date', '=', None), - ], - ('active', '=', True), - ]) - requests2 = cls.search([ - ('act_from', '=', user), - ('act_to', '!=', user), - ('state', '!=', 'draft'), - ('active', '=', True), - ]) - return ([r.id for r in requests], [r.id for r in requests2]) - - -class RequestLink(ModelSQL, ModelView): - "Request link" - __name__ = 'res.request.link' - name = fields.Char('Name', required=True, translate=True) - model = fields.Selection('models_get', 'Model', required=True) - priority = fields.Integer('Priority', required=True) - - @classmethod - def __setup__(cls): - super(RequestLink, cls).__setup__() - cls._order.insert(0, ('priority', 'ASC')) - - @staticmethod - def default_priority(): - return 5 - - @staticmethod - def models_get(): - pool = Pool() - Model = pool.get('ir.model') - models = Model.search([]) - res = [] - for model in models: - res.append((model.model, model.name)) - return res - - -class RequestHistory(ModelSQL, ModelView): - "Request history" - __name__ = 'res.request.history' - name = fields.Char('Summary', required=True, readonly=True) - request = fields.Many2One('res.request', 'Request', required=True, - ondelete='CASCADE', select=True, readonly=True) - act_from = fields.Many2One('res.user', 'From', required=True, - readonly=True) - act_to = fields.Many2One('res.user', 'To', required=True, readonly=True) - body = fields.Text('Body', readonly=True) - date_sent = fields.DateTime('Date sent', required=True, readonly=True) - state = fields.Selection(_STATES, 'State', required=True, readonly=True) - subject = fields.Char('Subject', required=True, readonly=True) - number_references = fields.Integer('References', readonly=True) - priority = fields.Selection(_PRIORITIES, 'Priority', required=True, - readonly=True) - - @classmethod - def __setup__(cls): - super(RequestHistory, cls).__setup__() - cls._order.insert(0, ('date_sent', 'DESC')) - - @staticmethod - def default_name(): - return 'No Name' - - @staticmethod - def default_act_from(): - return int(Transaction().user) - - @staticmethod - def default_act_to(): - return int(Transaction().user) - - @staticmethod - def default_date_sent(): - return datetime.datetime.now() - - @staticmethod - def write(records, vals): - pass - - -class RequestReference(ModelSQL, ModelView): - "Request Reference" - __name__ = 'res.request.reference' - _rec_name = 'reference' - - request = fields.Many2One('res.request', 'Request', required=True, - ondelete="CASCADE", select=True) - reference = fields.Reference('Reference', selection='links_get', - required=True) - - @staticmethod - def links_get(): - pool = Pool() - RequestLink = pool.get('res.request.link') - request_links = RequestLink.search([]) - return [(x.model, x.name) for x in request_links] diff --git a/trytond/res/request.xml b/trytond/res/request.xml deleted file mode 100644 index 649796ce5f..0000000000 --- a/trytond/res/request.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - res.request - tree - request_list - - - res.request - form - request_form - - - Requests - res.request - - - - - - - - - - - - - - - - - - - res.request.link - form - request_link_form - - - res.request.link - tree - request_link_list - - - Request Links - res.request.link - - - - - - - - - - - - - - - - - - - res.request.history - tree - request_history_list - - - res.request.history - form - request_history_form - - - - res.request.reference - tree - request_reference_list - - - res.request.reference - form - request_reference_form - - - diff --git a/trytond/res/tryton.cfg b/trytond/res/tryton.cfg index d46848b4b0..b59766d33b 100644 --- a/trytond/res/tryton.cfg +++ b/trytond/res/tryton.cfg @@ -5,5 +5,4 @@ xml: res.xml group.xml user.xml - request.xml ir.xml diff --git a/trytond/res/view/request_form.xml b/trytond/res/view/request_form.xml deleted file mode 100644 index a4225012f1..0000000000 --- a/trytond/res/view/request_form.xml +++ /dev/null @@ -1,40 +0,0 @@ - - -
-