commit
a28edaaeff
|
@ -35,7 +35,7 @@ class res_users(Model):
|
|||
|
||||
# Private Function section
|
||||
def _get_translation(self, cr, lang, text):
|
||||
context = {'lang': lang}
|
||||
context = {'lang': lang} # noqa: _() checks page for locals
|
||||
return _(text)
|
||||
|
||||
def _send_email_passkey(self, cr, user_id, user_agent_env):
|
||||
|
|
|
@ -36,7 +36,8 @@ def init(self, params):
|
|||
base_location=self.httprequest.url_root.rstrip('/'),
|
||||
HTTP_HOST=self.httprequest.environ['HTTP_HOST'],
|
||||
REMOTE_ADDR=self.httprequest.environ['REMOTE_ADDR']
|
||||
))
|
||||
)
|
||||
)
|
||||
|
||||
WebRequest.init = init
|
||||
|
||||
|
|
|
@ -34,13 +34,15 @@ try:
|
|||
try:
|
||||
import pymssql
|
||||
CONNECTORS.append(('mssql', 'Microsoft SQL Server'))
|
||||
except:
|
||||
assert pymssql
|
||||
except ImportError, AssertionError:
|
||||
_logger.info('MS SQL Server not available. Please install "pymssql"\
|
||||
python package.')
|
||||
try:
|
||||
import MySQLdb
|
||||
CONNECTORS.append(('mysql', 'MySQL'))
|
||||
except:
|
||||
assert MySQLdb
|
||||
except ImportError, AssertionError:
|
||||
_logger.info('MySQL not available. Please install "mysqldb"\
|
||||
python package.')
|
||||
except:
|
||||
|
@ -171,5 +173,3 @@ Sample connection strings:
|
|||
# TODO: if OK a (wizard) message box should be displayed
|
||||
raise orm.except_orm(_("Connection test succeeded!"),
|
||||
_("Everything seems properly set up!"))
|
||||
|
||||
#EOF
|
||||
|
|
|
@ -77,13 +77,18 @@ And it will be evaluated to
|
|||
Example city
|
||||
Example Corp footer
|
||||
|
||||
Given the way evaluation works internally (body_text of the template template is evaluated two times, first with the instance of email.template of your own template, then with the object your template refers to), you can do some trickery if you know that a template template is always used with the same kind of model (that is, models that have the same field name):
|
||||
Given the way evaluation works internally (body_text of the template template
|
||||
is evaluated two times, first with the instance of email.template of your own
|
||||
template, then with the object your template refers to), you can do some
|
||||
trickery if you know that a template template is always used with the same
|
||||
kind of model (that is, models that have the same field name):
|
||||
|
||||
In your template template:
|
||||
|
||||
::
|
||||
|
||||
Dear ${'${object.name}'}, <-- gets evaluated to "${object.name}" in the first step, then to the content of object.name
|
||||
Dear ${'${object.name}'}, <-- gets evaluated to "${object.name}" in the
|
||||
first step, then to the content of object.name
|
||||
${object.body_html}
|
||||
Best,
|
||||
Example Corp
|
||||
|
|
|
@ -26,9 +26,13 @@
|
|||
'description': """
|
||||
This module allows to create configurable calendars.
|
||||
|
||||
Through the 'calendar configurator' object, you can specify which models have to be merged in the super calendar. For each model, you have to define the 'description' and 'date_start' fields at least. Then you can define 'duration' and the 'user_id' fields.
|
||||
Through the 'calendar configurator' object, you can specify which models have
|
||||
to be merged in the super calendar. For each model, you have to define the
|
||||
'description' and 'date_start' fields at least. Then you can define 'duration'
|
||||
and the 'user_id' fields.
|
||||
|
||||
The 'super.calendar' object contains the the merged calendars. The 'super.calendar' can be updated by 'ir.cron' or manually.
|
||||
The 'super.calendar' object contains the the merged calendars. The
|
||||
'super.calendar' can be updated by 'ir.cron' or manually.
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
@ -37,7 +41,8 @@ After installing the module you can go to
|
|||
|
||||
Super calendar → Configuration → Configurators
|
||||
|
||||
and create a new configurator. For instance, if you want to see meetings and phone calls, you can create the following lines
|
||||
and create a new configurator. For instance, if you want to see meetings and
|
||||
phone calls, you can create the following lines
|
||||
|
||||
.. image:: http://planet.domsense.com/wp-content/uploads/2012/04/meetings.png
|
||||
:width: 400 px
|
||||
|
@ -45,7 +50,8 @@ and create a new configurator. For instance, if you want to see meetings and pho
|
|||
.. image:: http://planet.domsense.com/wp-content/uploads/2012/04/phone_calls.png
|
||||
:width: 400 px
|
||||
|
||||
Then, you can use the ‘Generate Calendar’ button or wait for the scheduled action (‘Generate Calendar Records’) to be run.
|
||||
Then, you can use the ‘Generate Calendar’ button or wait for the scheduled
|
||||
action (‘Generate Calendar Records’) to be run.
|
||||
|
||||
When the calendar is generated, you can visualize it by the ‘super calendar’ main menu.
|
||||
|
||||
|
@ -59,7 +65,11 @@ And here is the weekly one:
|
|||
.. image:: http://planet.domsense.com/wp-content/uploads/2012/04/week_calendar.png
|
||||
:width: 400 px
|
||||
|
||||
As you can see, several filters are available. A typical usage consists in filtering by ‘Configurator’ (if you have several configurators, ‘Scheduled calls and meetings’ can be one of them) and by your user. Once you filtered, you can save the filter as ‘Advanced filter’ or even add it to a dashboard.
|
||||
As you can see, several filters are available. A typical usage consists in
|
||||
filtering by ‘Configurator’ (if you have several configurators,
|
||||
‘Scheduled calls and meetings’ can be one of them) and by your user.
|
||||
Once you filtered, you can save the filter as ‘Advanced filter’ or even
|
||||
add it to a dashboard.
|
||||
""",
|
||||
'author': 'Agile Business Group',
|
||||
'website': 'http://www.agilebg.com',
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import fields, osv, orm
|
||||
from openerp.osv import fields, orm
|
||||
from openerp.tools.translate import _
|
||||
import logging
|
||||
from mako.template import Template
|
||||
|
@ -27,12 +27,14 @@ from datetime import datetime
|
|||
from openerp import tools
|
||||
from openerp.tools.safe_eval import safe_eval
|
||||
|
||||
|
||||
def _models_get(self, cr, uid, context=None):
|
||||
obj = self.pool.get('ir.model')
|
||||
ids = obj.search(cr, uid, [])
|
||||
res = obj.read(cr, uid, ids, ['model', 'name'], context)
|
||||
return [(r['model'], r['name']) for r in res]
|
||||
|
||||
|
||||
class super_calendar_configurator(orm.Model):
|
||||
_logger = logging.getLogger('super.calendar')
|
||||
_name = 'super.calendar.configurator'
|
||||
|
@ -60,19 +62,29 @@ class super_calendar_configurator(orm.Model):
|
|||
|
||||
for current_record_id in current_record_ids:
|
||||
current_record = current_pool.browse(cr, uid, current_record_id, context=context)
|
||||
if line.user_field_id and \
|
||||
current_record[line.user_field_id.name] and current_record[line.user_field_id.name]._table_name != 'res.users':
|
||||
raise osv.except_osv(_('Error'),
|
||||
if (line.user_field_id and
|
||||
current_record[line.user_field_id.name] and
|
||||
current_record[line.user_field_id.name]._table_name != 'res.users'):
|
||||
raise orm.except_orm(
|
||||
_('Error'),
|
||||
_("The 'User' field of record %s (%s) does not refer to res.users")
|
||||
% (current_record[line.description_field_id.name], line.name.model))
|
||||
if (((line.description_field_id
|
||||
and current_record[line.description_field_id.name])
|
||||
or line.description_code)
|
||||
and current_record[line.date_start_field_id.name]):
|
||||
if (((line.description_field_id and current_record[line.description_field_id.name]) or
|
||||
line.description_code) and
|
||||
current_record[line.date_start_field_id.name]):
|
||||
duration = False
|
||||
if not line.duration_field_id and line.date_stop_field_id and current_record[line.date_start_field_id.name] and current_record[line.date_stop_field_id.name]:
|
||||
date_start= datetime.strptime(current_record[line.date_start_field_id.name], tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
date_stop= datetime.strptime(current_record[line.date_stop_field_id.name], tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
if (not line.duration_field_id and
|
||||
line.date_stop_field_id and
|
||||
current_record[line.date_start_field_id.name] and
|
||||
current_record[line.date_stop_field_id.name]):
|
||||
date_start = datetime.strptime(
|
||||
current_record[line.date_start_field_id.name],
|
||||
tools.DEFAULT_SERVER_DATETIME_FORMAT
|
||||
)
|
||||
date_stop = datetime.strptime(
|
||||
current_record[line.date_stop_field_id.name],
|
||||
tools.DEFAULT_SERVER_DATETIME_FORMAT
|
||||
)
|
||||
duration = (date_stop - date_start).total_seconds() / 3600
|
||||
elif line.duration_field_id:
|
||||
duration = current_record[line.duration_field_id.name]
|
||||
|
@ -87,7 +99,12 @@ class super_calendar_configurator(orm.Model):
|
|||
'model_description': line.description,
|
||||
'date_start': current_record[line.date_start_field_id.name],
|
||||
'duration': duration,
|
||||
'user_id': line.user_field_id and current_record[line.user_field_id.name] and current_record[line.user_field_id.name].id or False,
|
||||
'user_id': (
|
||||
line.user_field_id and
|
||||
current_record[line.user_field_id.name] and
|
||||
current_record[line.user_field_id.name].id or
|
||||
False
|
||||
),
|
||||
'configurator_id': configurator.id,
|
||||
'res_id': line.name.model+','+str(current_record['id']),
|
||||
'model_id': line.name.id,
|
||||
|
@ -108,17 +125,26 @@ class super_calendar_configurator_line(orm.Model):
|
|||
('field', 'Field'),
|
||||
('code', 'Code'),
|
||||
], string="Description Type"),
|
||||
'description_field_id': fields.many2one('ir.model.fields', 'Description field',
|
||||
'description_field_id': fields.many2one(
|
||||
'ir.model.fields', 'Description field',
|
||||
domain="[('model_id', '=', name),('ttype', '=', 'char')]"),
|
||||
'description_code': fields.text('Description field', help="Use '${o}' to refer to the involved object. E.g.: '${o.project_id.name}'"),
|
||||
'date_start_field_id': fields.many2one('ir.model.fields', 'Start date field',
|
||||
'description_code': fields.text(
|
||||
'Description field',
|
||||
help="Use '${o}' to refer to the involved object. E.g.: '${o.project_id.name}'"
|
||||
),
|
||||
'date_start_field_id': fields.many2one(
|
||||
'ir.model.fields', 'Start date field',
|
||||
domain="['&','|',('ttype', '=', 'datetime'),('ttype', '=', 'date'),('model_id', '=', name)]",
|
||||
required=True),
|
||||
'date_stop_field_id': fields.many2one('ir.model.fields', 'End date field',
|
||||
domain="['&',('ttype', '=', 'datetime'),('model_id', '=', name)]"),
|
||||
'duration_field_id': fields.many2one('ir.model.fields', 'Duration field',
|
||||
'date_stop_field_id': fields.many2one(
|
||||
'ir.model.fields', 'End date field',
|
||||
domain="['&',('ttype', '=', 'datetime'),('model_id', '=', name)]"
|
||||
),
|
||||
'duration_field_id': fields.many2one(
|
||||
'ir.model.fields', 'Duration field',
|
||||
domain="['&',('ttype', '=', 'float'),('model_id', '=', name)]"),
|
||||
'user_field_id': fields.many2one('ir.model.fields', 'User field',
|
||||
'user_field_id': fields.many2one(
|
||||
'ir.model.fields', 'User field',
|
||||
domain="['&',('ttype', '=', 'many2one'),('model_id', '=', name)]"),
|
||||
}
|
||||
|
||||
|
|
|
@ -59,4 +59,3 @@ user's ldap record's attribute named [attribute].
|
|||
'python': ['ldap'],
|
||||
},
|
||||
}
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -23,7 +23,7 @@ from openerp.osv import fields, orm
|
|||
import logging
|
||||
import users_ldap_groups_operators
|
||||
import inspect
|
||||
import sys
|
||||
|
||||
|
||||
class CompanyLDAPGroupMapping(orm.Model):
|
||||
_name = 'res.company.ldap.group_mapping'
|
||||
|
@ -32,44 +32,52 @@ class CompanyLDAPGroupMapping(orm.Model):
|
|||
|
||||
def _get_operators(self, cr, uid, context=None):
|
||||
operators = []
|
||||
for name, operator in inspect.getmembers(users_ldap_groups_operators,
|
||||
members = inspect.getmembers(
|
||||
users_ldap_groups_operators,
|
||||
lambda cls: inspect.isclass(cls)
|
||||
and cls!=users_ldap_groups_operators.LDAPOperator):
|
||||
and cls != users_ldap_groups_operators.LDAPOperator)
|
||||
for name, operator in members:
|
||||
operators.append((name, name))
|
||||
return tuple(operators)
|
||||
|
||||
_columns = {
|
||||
'ldap_id': fields.many2one('res.company.ldap', 'LDAP server',
|
||||
required=True),
|
||||
'ldap_attribute': fields.char('LDAP attribute', size=64,
|
||||
'ldap_id': fields.many2one('res.company.ldap', 'LDAP server', required=True),
|
||||
'ldap_attribute': fields.char(
|
||||
'LDAP attribute', size=64,
|
||||
help='The LDAP attribute to check.\n'
|
||||
'For active directory, use memberOf.'),
|
||||
'operator': fields.selection(_get_operators, 'Operator',
|
||||
'operator': fields.selection(
|
||||
_get_operators, 'Operator',
|
||||
help='The operator to check the attribute against the value\n'
|
||||
'For active directory, use \'contains\'', required=True),
|
||||
'value': fields.char('Value', size=1024,
|
||||
'value': fields.char(
|
||||
'Value', size=1024,
|
||||
help='The value to check the attribute against.\n'
|
||||
'For active directory, use the dn of the desired group',
|
||||
required=True),
|
||||
'group': fields.many2one('res.groups', 'OpenERP group',
|
||||
'group': fields.many2one(
|
||||
'res.groups', 'OpenERP group',
|
||||
help='The OpenERP group to assign', required=True),
|
||||
}
|
||||
|
||||
|
||||
class CompanyLDAP(orm.Model):
|
||||
_inherit = 'res.company.ldap'
|
||||
|
||||
_columns = {
|
||||
'group_mappings': fields.one2many('res.company.ldap.group_mapping',
|
||||
'group_mappings': fields.one2many(
|
||||
'res.company.ldap.group_mapping',
|
||||
'ldap_id', 'Group mappings',
|
||||
help='Define how OpenERP groups are assigned to ldap users'),
|
||||
'only_ldap_groups': fields.boolean('Only ldap groups',
|
||||
'only_ldap_groups': fields.boolean(
|
||||
'Only ldap groups',
|
||||
help='If this is checked, manual changes to group membership are '
|
||||
'undone on every login (so OpenERP groups are always synchronous '
|
||||
'with LDAP groups). If not, manually added groups are preserved.')
|
||||
}
|
||||
|
||||
_default = {
|
||||
'only_ldap_groups': False
|
||||
'only_ldap_groups': False,
|
||||
}
|
||||
|
||||
def get_or_create_user(self, cr, uid, conf, login, ldap_entry, context=None):
|
||||
|
@ -83,10 +91,10 @@ class CompanyLDAP(orm.Model):
|
|||
conf_all = self.read(cr, uid, conf['id'], ['only_ldap_groups'])
|
||||
if(conf_all['only_ldap_groups']):
|
||||
logger.debug('deleting all groups from user %d' % user_id)
|
||||
userobj.write(cr, uid, [user_id], {'groups_id': [(5, )]})
|
||||
userobj.write(cr, uid, [user_id], {'groups_id': [(5, )]}, context=context)
|
||||
|
||||
for mapping in mappingobj.read(cr, uid, mappingobj.search(cr, uid,
|
||||
[('ldap_id', '=', conf['id'])]), []):
|
||||
for mapping in mappingobj.read(cr, uid, mappingobj.search(
|
||||
cr, uid, [('ldap_id', '=', conf['id'])]), []):
|
||||
operator = getattr(users_ldap_groups_operators, mapping['operator'])()
|
||||
logger.debug('checking mapping %s' % mapping)
|
||||
if operator.check_value(ldap_entry, mapping['ldap_attribute'],
|
||||
|
@ -94,5 +102,6 @@ class CompanyLDAP(orm.Model):
|
|||
logger.debug('adding user %d to group %s' %
|
||||
(user_id, mapping['group'][1]))
|
||||
userobj.write(cr, uid, [user_id],
|
||||
{'groups_id': [(4, mapping['group'][0])]})
|
||||
{'groups_id': [(4, mapping['group'][0])]},
|
||||
context=context)
|
||||
return user_id
|
||||
|
|
|
@ -20,24 +20,27 @@
|
|||
##############################################################################
|
||||
from string import Template
|
||||
|
||||
|
||||
class LDAPOperator:
|
||||
pass
|
||||
|
||||
|
||||
class contains(LDAPOperator):
|
||||
def check_value(self, ldap_entry, attribute, value, ldap_config, company,
|
||||
logger):
|
||||
def check_value(self, ldap_entry, attribute, value, ldap_config, company, logger):
|
||||
return (attribute in ldap_entry[1]) and (value in ldap_entry[1][attribute])
|
||||
|
||||
|
||||
class equals(LDAPOperator):
|
||||
def check_value(self, ldap_entry, attribute, value, ldap_config, company,
|
||||
logger):
|
||||
return (attribute in ldap_entry[1]) and (str(value)==str(ldap_entry[1][attribute]))
|
||||
def check_value(self, ldap_entry, attribute, value, ldap_config, company, logger):
|
||||
return attribute in ldap_entry[1] and unicode(value) == unicode(ldap_entry[1][attribute])
|
||||
|
||||
|
||||
class query(LDAPOperator):
|
||||
def check_value(self, ldap_entry, attribute, value, ldap_config, company,
|
||||
logger):
|
||||
query_string=Template(value).safe_substitute(dict([(attribute,
|
||||
ldap_entry[1][attribute][0]) for attribute in ldap_entry[1]]))
|
||||
def check_value(self, ldap_entry, attribute, value, ldap_config, company, logger):
|
||||
query_string = Template(value).safe_substitute(dict(
|
||||
[(attr, ldap_entry[1][attribute][0]) for attr in ldap_entry[1]]
|
||||
)
|
||||
)
|
||||
logger.debug('evaluating query group mapping, filter: %s' % query_string)
|
||||
results = company.query(ldap_config, query_string)
|
||||
logger.debug(results)
|
||||
|
|
|
@ -37,4 +37,3 @@ AD also supports the "mail" attribute, so it can be mapped into OpenERP.
|
|||
],
|
||||
'installable': True,
|
||||
}
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -24,13 +24,16 @@ from openerp.osv import fields, orm
|
|||
import logging
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CompanyLDAP(orm.Model):
|
||||
_inherit = 'res.company.ldap'
|
||||
_columns = {
|
||||
'name_attribute': fields.char('Name Attribute', size=64,
|
||||
'name_attribute': fields.char(
|
||||
'Name Attribute', size=64,
|
||||
help="By default 'cn' is used. "
|
||||
"For ActiveDirectory you might use 'displayName' instead."),
|
||||
'mail_attribute': fields.char('E-mail attribute', size=64,
|
||||
'mail_attribute': fields.char(
|
||||
'E-mail attribute', size=64,
|
||||
help="LDAP attribute to use to retrieve em-mail address."),
|
||||
}
|
||||
_defaults = {
|
||||
|
@ -71,4 +74,3 @@ class CompanyLDAP(orm.Model):
|
|||
_log.warning('No LDAP attribute "%s" found for login "%s"' % (
|
||||
conf.get(conf_name), values.get('login')))
|
||||
return values
|
||||
|
||||
|
|
|
@ -19,9 +19,10 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import osv, fields
|
||||
from osv import orm, fields
|
||||
|
||||
class CompanyLDAPPopulateWizard(osv.TransientModel):
|
||||
|
||||
class CompanyLDAPPopulateWizard(orm.TransientModel):
|
||||
_name = 'res.company.ldap.populate_wizard'
|
||||
_description = 'Populate users from LDAP'
|
||||
_columns = {
|
||||
|
@ -34,7 +35,6 @@ class CompanyLDAPPopulateWizard(osv.TransientModel):
|
|||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
ldap_pool = self.pool.get('res.company.ldap')
|
||||
users_pool = self.pool.get('res.users')
|
||||
if 'ldap_id' in vals:
|
||||
vals['users_created'] = ldap_pool.action_populate(
|
||||
cr, uid, vals['ldap_id'], context=context)
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
|
||||
import re
|
||||
from ldap.filter import filter_format
|
||||
from openerp.osv import orm, fields
|
||||
import openerp.exceptions
|
||||
from openerp.osv import orm
|
||||
import logging
|
||||
|
||||
|
||||
class CompanyLDAP(orm.Model):
|
||||
_inherit = 'res.company.ldap'
|
||||
|
||||
|
@ -54,7 +54,7 @@ class CompanyLDAP(orm.Model):
|
|||
if attribute_match:
|
||||
login_attr = attribute_match.group(1)
|
||||
else:
|
||||
raise osv.except_osv(
|
||||
raise orm.except_orm(
|
||||
"No login attribute found",
|
||||
"Could not extract login attribute from filter %s" %
|
||||
conf['ldap_filter'])
|
||||
|
|
Loading…
Reference in New Issue