Commit 1a3001a4 authored by jssuzanne's avatar jssuzanne
Browse files

Simplify models

--HG--
branch : 8.0
parent a3716933a4b4
# -*- coding: utf-8 -*-
#flake8: noqa
import process
# flake8: noqa
import connection
import entity
import exchange
import queue
import consumer
import message
import trigger
import wizard
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
......@@ -22,7 +22,7 @@
# v3 or later along with this program.
# If not, see <http://www.gnu.org/licenses/>.
{
'name': 'AnyBus Core',
'name': 'AnyBus',
'version': '0.3',
'category': 'Anybus',
'description': """
......@@ -45,7 +45,6 @@
'wizard/anybus_installer.xml',
],
'demo_xml': [
'demo/demo.xml',
],
'installable': True,
'application': True,
......
# -*- coding: utf-8 -*-
from odoo import models, fields
from openerp import models, fields
class anybusConnection(models.Model):
......@@ -21,21 +21,12 @@ class anybusConnection(models.Model):
default='disconnected', readonly=True,
)
def _get_url(self):
"""
return the url of the connexion
"""
return self.url
broker_connection = None
def action_declare_all(self):
"""
This function searches all exchanges, queues and binding,
and declare it in rabbitmq
"""
def action_purge(self, queue):
pass
# TODO
def action_purge_all(self):
"""
Purge all queues
"""
def publish(self, exchange, routing_key, data, contenttype):
pass
# TODO
# -*- coding: utf-8 -*-
from openerp import models, fields
class AnybusConsumer(models.Model):
_name = 'anybus.consumer'
_description = 'Anybus Consumer'
name = fields.Char(required=True)
queue = fields.Char(required=True)
# -*- coding: utf-8 -*-
from kombu import Connection
from osv import osv, fields
from tools.translate import _
class AbstractAnybusEntity(osv.AbstractModel):
""" Abstract class used to define the columns and common methods between exchanges and queues
"""
_name = 'abstract.anybus.entity'
_description = 'Abstract anybus entity'
_columns = {
'name': fields.char(
'Name of the entity', size=64, required=True,
states={'declared': [('readonly', True)]},
help="You can use %(dbname)s to add the base name in name"),
'connection_id': fields.many2one(
'anybus.connection', 'Connection',
states={'declared': [('readonly', True)]}, required=True),
'durable': fields.boolean(
'Durable', states={'declared': [('readonly', True)]}, help=(
"Durable entity remain active when a server restarts."
" Non-durable enity (transient entity) are purged "
"when a server restarts.")),
'auto_delete': fields.boolean(
'Auto delete', states={'declared': [('readonly', True)]}, help=(
"If set, the entity is deleted when "
"all entities have finished using it.")),
'arguments': fields.char(
'Arguments', size=255, required=True,
states={'declared': [('readonly', True)]},
help='Additional arguments to specify when the entity is '
'declared.'),
'already_declared': fields.boolean(
'Alread declared', states={'declared': [('readonly', True)]}),
'state': fields.selection(
[('draft', 'Draft'), ('declared', 'Declared')], 'State'),
}
_defaults = {
'durable': lambda *a: True,
'auto_delete': lambda *a: False,
'arguments': lambda *a: '{}',
'already_declared': lambda *a: False,
'state': lambda *a: 'draft',
}
def copy(self, cr, uid, id, default=None, context=None):
""" This method duplicates the entity. By default, the new entity is in draft state
and bears the name of copied entity, preceded by the word "Copie"
:param id: id of entity (ie. exchange or queue)
"""
if default is None:
default = {}
entity = self.browse(cr, uid, id, context=context)
default.update({'state': 'draft', 'name': 'Copie ' + entity.name})
return super(AbstractAnybusEntity, self).copy(
cr, uid, id, default, context=context)
def unlink(self, cr, uid, ids, context=None):
""" This method delete the entity, only if she's in the draft state
:param ids: list of entity_ids to delete
"""
for entity in self.browse(cr, uid, ids, context=context):
if entity.state != 'draft':
raise osv.except_osv(
_('Entity error'),
_('Only the draft entity can be being delete'))
return super(AbstractAnybusEntity, self).unlink(
cr, uid, ids, context=context)
def name_get(self, cr, uid, ids, context=None):
""" Default name_get of entity class
:param ids: list of entity_ids to delete
"""
if not len(ids):
return []
res = {}
for id in ids:
res[id] = self._get_entity_name(cr, uid, id, context=context)
return res.items()
def _get_entity_name(self, cr, uid, id, context=None):
""" Return the entity's name
:param id: entity's id
"""
r = self.read(cr, uid, id, ['name'], context=context)
return r['name'] % {'dbname': cr.dbname}
def _get_entity(self, cr, uid, entity, channel, context=None, **kwargs):
raise osv.except_osv(_('Entity error'), _('No entity defined'))
def _get_already_declared_entity(self, cr, uid, entity, channel,
context=None, **kwargs):
raise osv.except_osv(_('Entity error'), _('No entity defined'))
def _action_entity_method(self, cr, uid, entity, channel, method,
context=None):
e = self._get_entity(cr, uid, entity, channel, context=context)
f = getattr(e, method)
f()
def _action_method(self, cr, uid, ids, method="declare", onerror=True,
write={'state': 'declared'}, context=None):
""" Method used to declare an entity. When an entity is declared,
her state become 'declare'.
:param ids: list of entity's id
"""
for entity in self.browse(cr, uid, ids, context=context):
if entity.connection_id.state == 'draft':
entity.connection_id.action_declare()
uri = self.pool.get('anybus.connection')._get_uri(
cr, uid, entity.connection_id, context=context)
try:
with Connection(uri) as conn:
self._action_entity_method(cr, uid, entity, conn.channel(),
method, context=context)
except Exception, e:
if onerror:
raise osv.except_osv(_('Entity error'), e)
if write:
entity.write(write)
def action_declare(self, cr, uid, ids, context=None):
self._action_method(cr, uid, ids, context=context)
def action_redraft(self, cr, uid, ids, context=None):
self._action_method(cr, uid, ids, method="delete", onerror=False,
write={'state': 'draft'}, context=context)
# vim:expandtab:smartindent:tabstop=4:softtabstop=2:shiftwidth=4:
# -*- coding: utf-8 -*-
from kombu import Exchange, Connection
from osv import osv, fields
import time
class AnybusExchange(osv.Model):
""" Class representing an exchange within the meaning of RabbitMQ.
The exchange is the point where a message can be deposited and from there, the message
will then follow a path to finally be placed in the queues or destination, where it will be
stored until use. Several different customer can send messages on the same exchange, and
several messages will follow the same mapping.
"""
_name = 'anybus.entity.exchange'
_description = 'anybus Exchange'
_inherit = 'abstract.anybus.entity'
_columns = {
'type': fields.selection(
[('direct', 'Direct'), ('topic', 'Topic'), ('fanout', 'Fanout'),
('headers', 'Headers')], 'Exchange types',
states={'declared': [('readonly', True)]}),
'delivery_mode': fields.selection(
[(1, 'Transient'), (2, 'Persistent')], 'Delivery mode',
states={'declared': [('readonly', True)]}),
}
_defaults = {
'type': lambda *a: 'direct',
'delivery_mode': lambda *a: 2,
}
_sql_constraints = [
('name_uniq', 'unique (name)',
'The name of the Entity must be unique !'),
]
def _get_entity(self, cr, uid, exchange, channel, context=None, **kwargs):
""" This function return an entity containing the informations of exchange and channel
:param exchange: Object exchange
:param channel: Object channel
:return: Object Exchange
"""
if context is None:
context = {}
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
ctx = {
'user': user,
'context': context,
'time': time,
'dbname': cr.dbname,
}
name = self._get_entity_name(cr, uid, exchange.id, context=context)
return Exchange(
name=name,
type=exchange.type,
channel=channel,
durable=exchange.durable,
auto_delete=exchange.auto_delete,
delivery_mode=exchange.delivery_mode,
arguments=eval(exchange.arguments, ctx),
)
def _get_already_declared_entity(self, cr, uid, exchange, channel,
context=None, **kwargs):
""" This function return declared entity
:param exchange: Object exchange
:param channel: Object channel
:return: Object Exchange
"""
name = self._get_entity_name(cr, uid, exchange.id, context=context)
return Exchange(
name=name,
channel=channel,
)
def publish(self, cr, uid, id, body, key, context=None):
""" Function used to publish a message on an exchange
:param body: body of our message
:param key: routing key
:param id: Exchange_id
.. Note::
In order to customize the directions taken by a message, system binding / routing
key is available. Each binding may define its own key binding which will be a
string identifying a precise mapping. Messages will in turn define a routing key
that will define through which the message must pass binding. A routing key is
simply written in the form of dot-separated identifier names.
"""
exchange = self.browse(cr, uid, id, context=context)
ex_name = self._get_entity_name(cr, uid, id, context=context)
uri = self.pool.get('anybus.connection')._get_uri(
cr, uid, exchange.connection_id, context=context)
with Connection(uri) as conn:
ex = Exchange(name=ex_name, channel=conn.channel())
message = ex.Message(body)
ex.publish(message, routing_key=key)
## vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * account
#
# -*- coding: utf-8 -*-
from openerp import models, fields
from osv import osv, fields
from tools.translate import _
import traceback
import sys
class AbstractAnybusCommonMessageFields(osv.AbstractModel):
_name = 'abstract.anybus.common.message.fields'
_columns = {
'onerror': fields.selection(
[('continue', 'Continue on the next data'),
('block', 'Block the fifo'),
('retry', 'Put at the end of the FIFO')], 'On error',
help="""If some data is on error you can "Continue"
with the next data and avoid blocking the FIFO,
or block the fifo with block or put in the end of the fifo and retry""",
required=True),
'delete_message': fields.boolean(
'Delete message',
help='If check, the message will be delete after process'),
'properties': fields.char('Properties', size=512,
help='Properties add of the message'),
}
_defaults = {
'onerror': lambda *a: 'continue',
'delete_message': lambda *a: True,
'properties': lambda *a: '{}',
}
class AbstractAnybusMessage(osv.AbstractModel):
_name = "abstract.anybus.message"
class AbstractAnybusMessage(models.Model):
_name = "anybus.message"
_description = "Abstract anybus message"
_inherit = [
'abstract.anybus.common.message.fields',
'ir.needaction_mixin',
]
_columns = {
'connection_id': fields.many2one(
'anybus.connection', 'Connection',
states={'draft': [('readonly', False)]}, readonly=True),
'user_id': fields.many2one(
'res.users', 'Process user', required=True,
states={'draft': [('readonly', False)]}, readonly=True),
'seq': fields.integer(
'Sequence', readonly=True,
states={'draft': [('readonly', False)]}),
'create_date': fields.datetime('Create Date', readonly=True),
'write_date': fields.datetime('Write Date', readonly=True),
'message': fields.binary('Message',
states={'draft': [('readonly', False)]},
readonly=True),
'result': fields.text('Result', readonly=True),
'state': fields.selection([('draft', 'Draft'), ('blocked', 'Blocked'),
('done', 'Done')], 'state', readonly=True),
}
_defaults = {
'user_id': lambda s, cr, uid, ids, c={}: uid,
'seq': lambda *a: 100,
'state': lambda *a: 'draft',
}
_default_values_reads = [
'onerror',
'delete_message',
]
_default_values_model = ''
def _needaction_domain_get(self, cr, uid, context=None):
return [('state', '=', 'blocked')]
def unlink(self, cr, uid, ids, context=None):
""" Method use to delete a list of message
"""
for message in self.browse(cr, uid, ids, context=context):
if message.state == "blocked":
raise osv.except_osv(_('Message error'),
_('You can\' t unlink a blocked message'))
return super(AbstractAnybusMessage, self).unlink(
cr, uid, ids, context=context)
def action_redraft(self, cr, uid, ids, context=None):
self.write(cr, uid, ids, {'state': 'draft'}, context=context)
def _action_process_message(self, cr, uid, message, context=None):
raise osv.except_osv(
_('Anybus Message'),
_('Action fordidden, this action must be inherit'))
def action_process_message(self, cr, uid, id, retry=False, context=None):
this = self.browse(cr, uid, id, context=context)
if this.onerror == 'continue' and this.state == 'blocked':
return True
try:
self._action_process_message(cr, uid, this, context=context)
if this.delete_message:
this.unlink()
else:
this.write({'state': 'done', 'result': 'Done'})
return True
except osv.except_osv, e:
if this.onerror == 'continue' or retry:
result = "".join(
traceback.format_exception(
*sys.exc_info())) + '\n' + repr(e)
this.write({'state': 'blocked', 'result': result})
elif this.onerror == 'retry':
return False
else:
raise
def action_process_messages(self, cr, uid, ids, context=None):
search_ids = self.search(
cr, uid, [('state', '=', 'draft')], context=context)
retry = []
for id in search_ids:
if not self.action_process_message(cr, uid, id, context=None):
retry.append(id)
for id in retry:
self.action_process_message(cr, uid, id, context=None)
consumer = fields.Many2one('anybus.consumer', required=True)
sequence = fields.Integer(required=True, default=100)
message = fields.Binary('Message', required=True),
contenttype = fields.Char(required=True)
error = fields.Text(required=True)
def on_change_defaut_values(self, cr, uid, ids, defaultvalues_id,
context=None):
res = {}
if defaultvalues_id and self._default_values_model:
obj = self.pool.get(self._default_values_model)
if obj:
read = obj.read(
cr, uid, defaultvalues_id, self._default_values_reads,
context=context, load='_classic_write')
del read['id']
res['value'] = read
return res
def _needaction_domain_get(self):
return []
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
def process(self):
pass
# TODO
# -*- coding: utf-8 -*-
from osv import osv, fields
from tools.translate import _
class AbstractAnybusProcess(osv.AbstractModel):
"""
"""
_name = 'abstract.anybus.process'
_description = 'Abstract anybus process'
_inherit_create_method = True
_unwanted_model = ''
def _get_model(self, cr, uid, model, context=None):
"""
"""
fields_obj = self.pool.get('ir.model.fields')
model_obj = self.pool.get('ir.model')
domain = [
('ttype', '=', 'many2one'),
('relation', '=', model),
]
if self._unwanted_model:
domain.append(('model', '!=', self._unwanted_model))
fields_ids = fields_obj.search(cr, uid, domain, context=context)
domain = [
('field_id', 'in', fields_ids),
]
model_ids = model_obj.search(cr, uid, domain, context=context)
res = model_obj.read(
cr, uid, model_ids, ['model', 'name'], context=context)
return [(r['model'], r['name']) for r in res]
def force_not_default(self, cr, uid, id, context=None):
"""
This function changes the value of field ``isdefault`` when it's True to
False for all ids différent to id in parameter.
:param id: id of process
"""
domain = [('isdefault', '=', True)]
if id is not None:
domain.append(('id', '!=', id))
ids = self.search(cr, uid, domain, context=context)
if ids:
self.write(cr, uid, ids, {'isdefault': False}, context=context)
def write(self, cr, uid, ids, values, context=None):
"""
modifies a process while making sure that has no more than one default process.
:param ids:
:param values:
"""
res = super(AbstractAnybusProcess, self).write(
cr, uid, ids, values, context=context)
if values.get('isdefault', False):
if len(ids) > 1:
raise osv.except_osv(
_('process Error'),
_('You can\'t define more than one default process'))
self.force_not_default(cr, uid, ids[0], context=context)
return res
def create(self, cr, uid, values, context=None):
"""
Method to create a process
"""
if context is None:
context = {}
ctx = context.copy()
field_id = values.get('field_id', None)
if field_id is None and context.get('process_model') is not None:
domain = [
('model_id.model', '=', context.get('process_model')),
('ttype', '=', 'many2one'),
('relation', '=', self._name),
]
fields_ids = self.pool.get('ir.model.fields').search(
cr, uid, domain, context=context)
if fields_ids:
values['field_id'] = fields_ids[0]
else:
ctx.update({'process_model': self._name})
id = super(AbstractAnybusProcess, self).create(
cr, uid, values, context=ctx)
if values.get('isdefault', False):
self.force_not_default(cr, uid, id, context=context)
if self._inherit_create_method:
this = self.browse(cr, uid, id, context=context)
process_id = this[this.field_id.name].id
obj = self.pool.get(this.field_id.relation)
obj.write(cr, uid, process_id,
{'real_process': '%s,%d' % (self._name, id)},
context=context)
return id
def _process_process(self, cr, uid, id, model, model_ids, context=None):
"""
"""
raise osv.except_osv(_('process error'), _('Undifined method'))
def process_process(self, cr, uid, id, model, model_ids, context=None):
"""
"""
this = self.browse(cr, uid, id, context=context)
process = this.real_process._name
process_id = this.real_process.id
obj = self.pool.get(process)
return obj._process_process(
cr, uid, process_id, model, model_ids, context=context)
class AbstractAnybusProcessTable(osv.AbstractModel):
"""
"""
_name = 'abstract.anybus.process.table'
_inherit = 'abstract.anybus.process'