[MERGE] bugfixes: default language for partners, password change, validation of custom selection fields, ...
See the bug links lp bug: https://launchpad.net/bugs/670264 fixed lp bug: https://launchpad.net/bugs/692891 fixed lp bug: https://launchpad.net/bugs/695678 fixed lp bug: https://launchpad.net/bugs/631547 fixed lp bug: https://launchpad.net/bugs/632927 fixed bzr revid: odo@openerp.com-20110106173828-kdv1gtdvbws1ceb5
This commit is contained in:
commit
7d3375f49f
|
@ -28,6 +28,8 @@
|
||||||
<field name="translatable">True</field>
|
<field name="translatable">True</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<function name="install_lang" model="res.lang"/>
|
||||||
|
|
||||||
<record id="ad" model="res.country">
|
<record id="ad" model="res.country">
|
||||||
<field name="name">Andorra, Principality of</field>
|
<field name="name">Andorra, Principality of</field>
|
||||||
<field name="code">ad</field>
|
<field name="code">ad</field>
|
||||||
|
|
|
@ -70,34 +70,6 @@
|
||||||
======================
|
======================
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<record id="view_change_user_password_form" model="ir.ui.view">
|
|
||||||
<field name="name">change.user.password</field>
|
|
||||||
<field name="model">change.user.password</field>
|
|
||||||
<field name="type">form</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="Change Password">
|
|
||||||
<field name="current_password" password="True" readonly="0" colspan="4"/>
|
|
||||||
<field name="new_password" password="True" readonly="0" colspan="4"/>
|
|
||||||
<field name="confirm_password" password="True" readonly="0" colspan="4"/>
|
|
||||||
<label colspan="1" string=""/>
|
|
||||||
<label colspan="3" string="You must logout and login again after changing your password."/>
|
|
||||||
<separator colspan="4" />
|
|
||||||
<label align="0.0" colspan="2" string=""/>
|
|
||||||
<button colspan="1" icon="gtk-cancel" special="cancel" string="Cancel"/>
|
|
||||||
<button colspan="1" icon="gtk-ok" name="change_password" string="Change" type="object"/>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="action_view_change_password_form" model="ir.actions.act_window">
|
|
||||||
<field name="name">Change Password</field>
|
|
||||||
<field name="type">ir.actions.act_window</field>
|
|
||||||
<field name="res_model">change.user.password</field>
|
|
||||||
<field name="view_type">form</field>
|
|
||||||
<field name="view_mode">form</field>
|
|
||||||
<field name="target">new</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="view_users_form_simple_modif" model="ir.ui.view">
|
<record id="view_users_form_simple_modif" model="ir.ui.view">
|
||||||
<field name="name">res.users.form.modif</field>
|
<field name="name">res.users.form.modif</field>
|
||||||
<field name="model">res.users</field>
|
<field name="model">res.users</field>
|
||||||
|
@ -119,8 +91,6 @@
|
||||||
<field name="context_lang" completion="1" readonly="0"/>
|
<field name="context_lang" completion="1" readonly="0"/>
|
||||||
<field name="context_tz" completion="1" readonly="0"/>
|
<field name="context_tz" completion="1" readonly="0"/>
|
||||||
<field name="menu_tips" colspan="2" readonly="0"/>
|
<field name="menu_tips" colspan="2" readonly="0"/>
|
||||||
<label string="" colspan="1"/>
|
|
||||||
<button name="%(action_view_change_password_form)d" string="Change Password" type="action" icon="gtk-execute"/>
|
|
||||||
<separator string="Email & Signature" colspan="4"/>
|
<separator string="Email & Signature" colspan="4"/>
|
||||||
<group colspan="4"><field name="user_email" widget="email" readonly="0"/></group>
|
<group colspan="4"><field name="user_email" widget="email" readonly="0"/></group>
|
||||||
<field colspan="4" name="signature" readonly="0" nolabel="1"/>
|
<field colspan="4" name="signature" readonly="0" nolabel="1"/>
|
||||||
|
@ -139,7 +109,7 @@
|
||||||
<field name="name" select="1"/>
|
<field name="name" select="1"/>
|
||||||
<field name="active"/>
|
<field name="active"/>
|
||||||
<field name="login" select="1"/>
|
<field name="login" select="1"/>
|
||||||
<field name="password" password="True"/>
|
<field name="new_password" password="True"/>
|
||||||
<newline/>
|
<newline/>
|
||||||
<notebook colspan="4">
|
<notebook colspan="4">
|
||||||
<page string="User">
|
<page string="User">
|
||||||
|
|
|
@ -19,14 +19,16 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
|
import time
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
from osv import fields,osv
|
from osv import fields,osv
|
||||||
import ir, re
|
import ir
|
||||||
import netsvc
|
import netsvc
|
||||||
from osv.orm import except_orm, browse_record
|
from osv.orm import except_orm, browse_record
|
||||||
|
|
||||||
import time
|
|
||||||
import tools
|
import tools
|
||||||
|
from tools.safe_eval import safe_eval as eval
|
||||||
from tools import config
|
from tools import config
|
||||||
from tools.translate import _
|
from tools.translate import _
|
||||||
import pooler
|
import pooler
|
||||||
|
@ -152,21 +154,29 @@ class ir_model_fields(osv.osv):
|
||||||
_description = "Fields"
|
_description = "Fields"
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Name', required=True, size=64, select=1),
|
'name': fields.char('Name', required=True, size=64, select=1),
|
||||||
'model': fields.char('Object Name', size=64, required=True, select=1),
|
'model': fields.char('Object Name', size=64, required=True, select=1,
|
||||||
'relation': fields.char('Object Relation', size=64),
|
help="The technical name of the model this field belongs to"),
|
||||||
'relation_field': fields.char('Relation Field', size=64),
|
'relation': fields.char('Object Relation', size=64,
|
||||||
'model_id': fields.many2one('ir.model', 'Object ID', required=True, select=True, ondelete='cascade'),
|
help="For relationship fields, the technical name of the target model"),
|
||||||
|
'relation_field': fields.char('Relation Field', size=64,
|
||||||
|
help="For one2many fields, the field on the target model that implement the opposite many2one relationship"),
|
||||||
|
'model_id': fields.many2one('ir.model', 'Model', required=True, select=True, ondelete='cascade',
|
||||||
|
help="The model this field belongs to"),
|
||||||
'field_description': fields.char('Field Label', required=True, size=256),
|
'field_description': fields.char('Field Label', required=True, size=256),
|
||||||
'ttype': fields.selection(_get_fields_type, 'Field Type',size=64, required=True),
|
'ttype': fields.selection(_get_fields_type, 'Field Type',size=64, required=True),
|
||||||
'selection': fields.char('Field Selection',size=128),
|
'selection': fields.char('Selection Options',size=128, help="List of options for a selection field, "
|
||||||
|
"specified as a Python expression defining a list of (key, label) pairs. "
|
||||||
|
"For example: [('blue','Blue'),('yellow','Yellow')]"),
|
||||||
'required': fields.boolean('Required'),
|
'required': fields.boolean('Required'),
|
||||||
'readonly': fields.boolean('Readonly'),
|
'readonly': fields.boolean('Readonly'),
|
||||||
'select_level': fields.selection([('0','Not Searchable'),('1','Always Searchable'),('2','Advanced Search')],'Searchable', required=True),
|
'select_level': fields.selection([('0','Not Searchable'),('1','Always Searchable'),('2','Advanced Search (deprecated)')],'Searchable', required=True),
|
||||||
'translate': fields.boolean('Translate'),
|
'translate': fields.boolean('Translate', help="Whether values for this field can be translated (enables the translation mechanism for that field)"),
|
||||||
'size': fields.integer('Size'),
|
'size': fields.integer('Size'),
|
||||||
'state': fields.selection([('manual','Custom Field'),('base','Base Field')],'Type', required=True, readonly=True, select=1),
|
'state': fields.selection([('manual','Custom Field'),('base','Base Field')],'Type', required=True, readonly=True, select=1),
|
||||||
'on_delete': fields.selection([('cascade','Cascade'),('set null','Set NULL')], 'On delete', help='On delete property for many2one fields'),
|
'on_delete': fields.selection([('cascade','Cascade'),('set null','Set NULL')], 'On delete', help='On delete property for many2one fields'),
|
||||||
'domain': fields.char('Domain', size=256),
|
'domain': fields.char('Domain', size=256, help="The optional domain to restrict possible values for relationship fields, "
|
||||||
|
"specified as a Python expression defining a list of triplets. "
|
||||||
|
"For example: [('color','=','red')]"),
|
||||||
'groups': fields.many2many('res.groups', 'ir_model_fields_group_rel', 'field_id', 'group_id', 'Groups'),
|
'groups': fields.many2many('res.groups', 'ir_model_fields_group_rel', 'field_id', 'group_id', 'Groups'),
|
||||||
'view_load': fields.boolean('View Auto-Load'),
|
'view_load': fields.boolean('View Auto-Load'),
|
||||||
'selectable': fields.boolean('Selectable'),
|
'selectable': fields.boolean('Selectable'),
|
||||||
|
@ -174,7 +184,7 @@ class ir_model_fields(osv.osv):
|
||||||
_rec_name='field_description'
|
_rec_name='field_description'
|
||||||
_defaults = {
|
_defaults = {
|
||||||
'view_load': lambda *a: 0,
|
'view_load': lambda *a: 0,
|
||||||
'selection': lambda *a: "[]",
|
'selection': lambda *a: "[('key','label')]",
|
||||||
'domain': lambda *a: "[]",
|
'domain': lambda *a: "[]",
|
||||||
'name': lambda *a: 'x_',
|
'name': lambda *a: 'x_',
|
||||||
'state': lambda self,cr,uid,ctx={}: (ctx and ctx.get('manual',False)) and 'manual' or 'base',
|
'state': lambda self,cr,uid,ctx={}: (ctx and ctx.get('manual',False)) and 'manual' or 'base',
|
||||||
|
@ -185,6 +195,25 @@ class ir_model_fields(osv.osv):
|
||||||
'selectable': lambda *a: 1,
|
'selectable': lambda *a: 1,
|
||||||
}
|
}
|
||||||
_order = "name"
|
_order = "name"
|
||||||
|
|
||||||
|
def _check_selection(self, cr, uid, ids, context=None):
|
||||||
|
selection_field = self.browse(cr, uid, ids[0], context=context)
|
||||||
|
try:
|
||||||
|
selection_list = eval(selection_field.selection)
|
||||||
|
except Exception:
|
||||||
|
logging.getLogger('ir.model').error('Invalid selection list definition for fields.selection %s', selection_field.name , exc_info=True)
|
||||||
|
return False
|
||||||
|
if not (isinstance(selection_list, list) and selection_list):
|
||||||
|
return False
|
||||||
|
for selection_item in selection_list:
|
||||||
|
if not (isinstance(selection_item, (tuple,list)) and len(selection_item) == 2):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
_constraints = [
|
||||||
|
(_check_selection, "Wrong list of values specified for a field of type selection, it should be written as [('key','value')]", ['selection'])
|
||||||
|
]
|
||||||
|
|
||||||
def _size_gt_zero_msg(self, cr, user, ids, context=None):
|
def _size_gt_zero_msg(self, cr, user, ids, context=None):
|
||||||
return _('Size of the field can never be less than 1 !')
|
return _('Size of the field can never be less than 1 !')
|
||||||
|
|
||||||
|
|
|
@ -257,12 +257,14 @@ class ir_ui_menu(osv.osv):
|
||||||
def read_image(self, path):
|
def read_image(self, path):
|
||||||
path_info = path.split(',')
|
path_info = path.split(',')
|
||||||
icon_path = addons.get_module_resource(path_info[0],path_info[1])
|
icon_path = addons.get_module_resource(path_info[0],path_info[1])
|
||||||
icon_file = tools.file_open(icon_path,'rb')
|
icon_image = False
|
||||||
try:
|
if icon_path:
|
||||||
icon = icon_file.read()
|
try:
|
||||||
return base64.encodestring(icon)
|
icon_file = tools.file_open(icon_path,'rb')
|
||||||
finally:
|
icon_image = base64.encodestring(icon_file.read())
|
||||||
icon_file.close()
|
finally:
|
||||||
|
icon_file.close()
|
||||||
|
return icon_image
|
||||||
|
|
||||||
def _get_image_icon(self, cr, uid, ids, name, args, context=None):
|
def _get_image_icon(self, cr, uid, ids, name, args, context=None):
|
||||||
res = {}
|
res = {}
|
||||||
|
@ -304,7 +306,7 @@ class ir_ui_menu(osv.osv):
|
||||||
('ir.actions.server', 'ir.actions.server'),
|
('ir.actions.server', 'ir.actions.server'),
|
||||||
]),
|
]),
|
||||||
}
|
}
|
||||||
|
|
||||||
def _rec_message(self, cr, uid, ids, context=None):
|
def _rec_message(self, cr, uid, ids, context=None):
|
||||||
return _('Error ! You can not create recursive Menu.')
|
return _('Error ! You can not create recursive Menu.')
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,7 @@ class res_partner(osv.osv):
|
||||||
'email': fields.related('address', 'email', type='char', size=240, string='E-mail'),
|
'email': fields.related('address', 'email', type='char', size=240, string='E-mail'),
|
||||||
'company_id': fields.many2one('res.company', 'Company', select=1),
|
'company_id': fields.many2one('res.company', 'Company', select=1),
|
||||||
}
|
}
|
||||||
|
|
||||||
def _default_category(self, cr, uid, context={}):
|
def _default_category(self, cr, uid, context={}):
|
||||||
if 'category_id' in context and context['category_id']:
|
if 'category_id' in context and context['category_id']:
|
||||||
return [context['category_id']]
|
return [context['category_id']]
|
||||||
|
|
|
@ -24,10 +24,66 @@ from locale import localeconv
|
||||||
import tools
|
import tools
|
||||||
from tools.safe_eval import safe_eval as eval
|
from tools.safe_eval import safe_eval as eval
|
||||||
from tools.translate import _
|
from tools.translate import _
|
||||||
|
import locale
|
||||||
|
import logging
|
||||||
|
|
||||||
class lang(osv.osv):
|
class lang(osv.osv):
|
||||||
_name = "res.lang"
|
_name = "res.lang"
|
||||||
_description = "Languages"
|
_description = "Languages"
|
||||||
|
|
||||||
|
def install_lang(self, cr, uid, **args):
|
||||||
|
lang_ids = self.search(cr, uid, [('code','=', tools.config.get('lang'))])
|
||||||
|
values_obj = self.pool.get('ir.values')
|
||||||
|
if not lang_ids:
|
||||||
|
lang_id = self.load_lang(cr, uid, tools.config.get('lang'))
|
||||||
|
default_value = values_obj.get(cr, uid, 'default', False, 'res.partner')
|
||||||
|
if not default_value:
|
||||||
|
values_obj.set(cr, uid, 'default', False, 'lang', ['res.partner'], tools.config.get('lang'))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def load_lang(self, cr, uid, lang, lang_name=None):
|
||||||
|
# create the language with locale information
|
||||||
|
fail = True
|
||||||
|
logger = logging.getLogger('i18n')
|
||||||
|
iso_lang = tools.get_iso_codes(lang)
|
||||||
|
for ln in tools.get_locales(lang):
|
||||||
|
try:
|
||||||
|
locale.setlocale(locale.LC_ALL, str(ln))
|
||||||
|
fail = False
|
||||||
|
break
|
||||||
|
except locale.Error:
|
||||||
|
continue
|
||||||
|
if fail:
|
||||||
|
lc = locale.getdefaultlocale()[0]
|
||||||
|
msg = 'Unable to get information for locale %s. Information from the default locale (%s) have been used.'
|
||||||
|
logger.warning(msg, lang, lc)
|
||||||
|
|
||||||
|
if not lang_name:
|
||||||
|
lang_name = tools.get_languages().get(lang, lang)
|
||||||
|
|
||||||
|
|
||||||
|
def fix_xa0(s):
|
||||||
|
if s == '\xa0':
|
||||||
|
return '\xc2\xa0'
|
||||||
|
return s
|
||||||
|
|
||||||
|
lang_info = {
|
||||||
|
'code': lang,
|
||||||
|
'iso_code': iso_lang,
|
||||||
|
'name': lang_name,
|
||||||
|
'translatable': 1,
|
||||||
|
'date_format' : str(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y')),
|
||||||
|
'time_format' : str(locale.nl_langinfo(locale.T_FMT)),
|
||||||
|
'decimal_point' : fix_xa0(str(locale.localeconv()['decimal_point'])),
|
||||||
|
'thousands_sep' : fix_xa0(str(locale.localeconv()['thousands_sep'])),
|
||||||
|
}
|
||||||
|
lang_id = False
|
||||||
|
try:
|
||||||
|
lang_id = self.create(cr, uid, lang_info)
|
||||||
|
finally:
|
||||||
|
tools.resetlocale()
|
||||||
|
return lang_id
|
||||||
|
|
||||||
def _get_default_date_format(self,cursor,user,context={}):
|
def _get_default_date_format(self,cursor,user,context={}):
|
||||||
return '%m/%d/%Y'
|
return '%m/%d/%Y'
|
||||||
|
|
||||||
|
@ -69,7 +125,7 @@ class lang(osv.osv):
|
||||||
thousands_sep = lang_obj.thousands_sep or conv[monetary and 'mon_thousands_sep' or 'thousands_sep']
|
thousands_sep = lang_obj.thousands_sep or conv[monetary and 'mon_thousands_sep' or 'thousands_sep']
|
||||||
decimal_point = lang_obj.decimal_point
|
decimal_point = lang_obj.decimal_point
|
||||||
grouping = lang_obj.grouping
|
grouping = lang_obj.grouping
|
||||||
return (grouping, thousands_sep, decimal_point)
|
return (grouping, thousands_sep, decimal_point)
|
||||||
|
|
||||||
def write(self, cr, uid, ids, vals, context=None):
|
def write(self, cr, uid, ids, vals, context=None):
|
||||||
for lang_id in ids :
|
for lang_id in ids :
|
||||||
|
@ -95,19 +151,19 @@ class lang(osv.osv):
|
||||||
|
|
||||||
def _group(self, cr, uid, ids, s, monetary=False, grouping=False, thousands_sep=''):
|
def _group(self, cr, uid, ids, s, monetary=False, grouping=False, thousands_sep=''):
|
||||||
grouping = eval(grouping)
|
grouping = eval(grouping)
|
||||||
|
|
||||||
if not grouping:
|
if not grouping:
|
||||||
return (s, 0)
|
return (s, 0)
|
||||||
|
|
||||||
result = ""
|
result = ""
|
||||||
seps = 0
|
seps = 0
|
||||||
spaces = ""
|
spaces = ""
|
||||||
|
|
||||||
if s[-1] == ' ':
|
if s[-1] == ' ':
|
||||||
sp = s.find(' ')
|
sp = s.find(' ')
|
||||||
spaces = s[sp:]
|
spaces = s[sp:]
|
||||||
s = s[:sp]
|
s = s[:sp]
|
||||||
|
|
||||||
while s and grouping:
|
while s and grouping:
|
||||||
# if grouping is -1, we are done
|
# if grouping is -1, we are done
|
||||||
if grouping[0] == -1:
|
if grouping[0] == -1:
|
||||||
|
@ -139,7 +195,7 @@ class lang(osv.osv):
|
||||||
if percent[0] != '%':
|
if percent[0] != '%':
|
||||||
raise ValueError("format() must be given exactly one %char format specifier")
|
raise ValueError("format() must be given exactly one %char format specifier")
|
||||||
|
|
||||||
lang_grouping, thousands_sep, decimal_point = self._lang_data_get(cr, uid, ids[0], monetary)
|
lang_grouping, thousands_sep, decimal_point = self._lang_data_get(cr, uid, ids[0], monetary)
|
||||||
|
|
||||||
formatted = percent % value
|
formatted = percent % value
|
||||||
# floats and decimal ints need special action!
|
# floats and decimal ints need special action!
|
||||||
|
|
|
@ -194,6 +194,16 @@ class users(osv.osv):
|
||||||
self.write(cr, uid, ids, {'address_id': address_id}, context)
|
self.write(cr, uid, ids, {'address_id': address_id}, context)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _set_new_password(self, cr, uid, id, name, value, args, context=None):
|
||||||
|
if not value:
|
||||||
|
raise osv.except_osv(_('Empty new password'), _('Please provide a new password value'))
|
||||||
|
if uid == id:
|
||||||
|
# To change their own password users must use the client-specific change password wizard,
|
||||||
|
# so that the new password is immediately used for further RPC requests, otherwise the user
|
||||||
|
# will face unexpected 'Access Denied' exceptions.
|
||||||
|
raise osv.except_osv(_('Operation Canceled'), _('Please use the change password wizard (in User Preferences or User menu) to change your own password.'))
|
||||||
|
self.write(cr, uid, id, {'password': value})
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('User Name', size=64, required=True, select=True,
|
'name': fields.char('User Name', size=64, required=True, select=True,
|
||||||
help="The new user's real name, used for searching"
|
help="The new user's real name, used for searching"
|
||||||
|
@ -201,6 +211,10 @@ class users(osv.osv):
|
||||||
'login': fields.char('Login', size=64, required=True,
|
'login': fields.char('Login', size=64, required=True,
|
||||||
help="Used to log into the system"),
|
help="Used to log into the system"),
|
||||||
'password': fields.char('Password', size=64, invisible=True, help="Keep empty if you don't want the user to be able to connect on the system."),
|
'password': fields.char('Password', size=64, invisible=True, help="Keep empty if you don't want the user to be able to connect on the system."),
|
||||||
|
'new_password': fields.function(lambda *a:'', method=True, type='char', size=64,
|
||||||
|
fnct_inv=_set_new_password,
|
||||||
|
string='Change password', help="Only specify a value if you want to change the user password. "
|
||||||
|
"This user will have to logout and login again!"),
|
||||||
'email': fields.char('E-mail', size=64,
|
'email': fields.char('E-mail', size=64,
|
||||||
help='If an email is provided, the user will be sent a message '
|
help='If an email is provided, the user will be sent a message '
|
||||||
'welcoming him.\n\nWarning: if "email_from" and "smtp_server"'
|
'welcoming him.\n\nWarning: if "email_from" and "smtp_server"'
|
||||||
|
@ -452,7 +466,7 @@ class users(osv.osv):
|
||||||
(int(uid), passwd, True))
|
(int(uid), passwd, True))
|
||||||
res = cr.fetchone()[0]
|
res = cr.fetchone()[0]
|
||||||
if not bool(res):
|
if not bool(res):
|
||||||
raise security.ExceptionNoTb('AccessDenied')
|
raise security.ExceptionNoTb('Accessenied')
|
||||||
if res:
|
if res:
|
||||||
if self._uid_cache.has_key(db):
|
if self._uid_cache.has_key(db):
|
||||||
ulist = self._uid_cache[db]
|
ulist = self._uid_cache[db]
|
||||||
|
@ -476,6 +490,18 @@ class users(osv.osv):
|
||||||
finally:
|
finally:
|
||||||
cr.close()
|
cr.close()
|
||||||
|
|
||||||
|
def change_password(self, cr, uid, old_passwd, new_passwd):
|
||||||
|
"""Change current user password. Old password must be provided explicitly
|
||||||
|
to prevent hijacking an existing user session, or for cases where the cleartext
|
||||||
|
password is not used to authenticate requests.
|
||||||
|
|
||||||
|
:return: True
|
||||||
|
:raise: security.ExceptionNoTb when old password is wrong
|
||||||
|
"""
|
||||||
|
if self.check(cr.dbname, uid, old_passwd):
|
||||||
|
self.write(cr, uid, uid, {'password': new_passwd})
|
||||||
|
return True
|
||||||
|
|
||||||
users()
|
users()
|
||||||
|
|
||||||
class config_users(osv.osv_memory):
|
class config_users(osv.osv_memory):
|
||||||
|
@ -574,39 +600,4 @@ class res_config_view(osv.osv_memory):
|
||||||
|
|
||||||
res_config_view()
|
res_config_view()
|
||||||
|
|
||||||
class change_user_password(osv.osv_memory):
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
_name = 'change.user.password'
|
|
||||||
_columns = {
|
|
||||||
'current_password':fields.char('Current Password', size=64, required=True, help="Enter your current password."),
|
|
||||||
'new_password': fields.char('New Password', size=64, required=True, help="Enter the new password."),
|
|
||||||
'confirm_password': fields.char('Confirm Password', size=64, required=True, help="Enter the new password again for confirmation."),
|
|
||||||
}
|
|
||||||
_defaults={
|
|
||||||
'current_password' : '',
|
|
||||||
'new_password' : '',
|
|
||||||
'confirm_password' : '',
|
|
||||||
}
|
|
||||||
|
|
||||||
def change_password(self, cr, uid, ids, context=None):
|
|
||||||
for form_id in ids:
|
|
||||||
password_rec = self.browse(cr, uid, form_id, context)
|
|
||||||
if password_rec.new_password != password_rec.confirm_password:
|
|
||||||
raise osv.except_osv(_('Error !'), _('The new and confirmation passwords do not match, please double-check them.'))
|
|
||||||
|
|
||||||
# Validate current password without reading it from database,
|
|
||||||
# as it could be stored differently (LDAP, encrypted/hashed, etc.)
|
|
||||||
is_correct_password = False
|
|
||||||
try:
|
|
||||||
user_obj = self.pool.get('res.users')
|
|
||||||
is_correct_password = user_obj.check(cr.dbname, uid, password_rec.current_password)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
if not is_correct_password:
|
|
||||||
raise osv.except_osv(_('Error !'), _('The current password does not match, please double-check it.'))
|
|
||||||
user_obj.write(cr, uid, [uid], {'password': password_rec.new_password}, context=context)
|
|
||||||
return {}
|
|
||||||
|
|
||||||
change_user_password()
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
||||||
|
|
|
@ -553,7 +553,7 @@ class many2many(_column):
|
||||||
DeprecationWarning, stacklevel=2)
|
DeprecationWarning, stacklevel=2)
|
||||||
obj = obj.pool.get(self._obj)
|
obj = obj.pool.get(self._obj)
|
||||||
|
|
||||||
# static domains are lists, and are evaluated both here and on client-side, while string
|
# static domains are lists, and are evaluated both here and on client-side, while string
|
||||||
# domains supposed by dynamic and evaluated on client-side only (thus ignored here)
|
# domains supposed by dynamic and evaluated on client-side only (thus ignored here)
|
||||||
# FIXME: make this distinction explicit in API!
|
# FIXME: make this distinction explicit in API!
|
||||||
domain = isinstance(self._domain, list) and self._domain or []
|
domain = isinstance(self._domain, list) and self._domain or []
|
||||||
|
@ -1049,7 +1049,8 @@ class property(function):
|
||||||
brs = properties.browse(cr, uid, nids, context=context)
|
brs = properties.browse(cr, uid, nids, context=context)
|
||||||
for prop in brs:
|
for prop in brs:
|
||||||
value = properties.get_by_record(cr, uid, prop, context=context)
|
value = properties.get_by_record(cr, uid, prop, context=context)
|
||||||
res[prop.res_id.id][prop.fields_id.name] = value or False
|
record_exists = obj.pool.get(value._name).exists(cr, uid, value.id)
|
||||||
|
res[prop.res_id.id][prop.fields_id.name] = (record_exists and value) and value or False
|
||||||
if value and (prop.type == 'many2one'):
|
if value and (prop.type == 'many2one'):
|
||||||
replaces.setdefault(value._name, {})
|
replaces.setdefault(value._name, {})
|
||||||
replaces[value._name][value.id] = True
|
replaces[value._name][value.id] = True
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
# OpenERP, Open Source Management Solution
|
# OpenERP, Open Source Management Solution
|
||||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||||
#
|
#
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
# GNU Affero General Public License for more details.
|
# GNU Affero General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# 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/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
@ -50,8 +50,8 @@ class db(netsvc.ExportService):
|
||||||
self._pg_psw_env_var_is_set = False # on win32, pg_dump need the PGPASSWORD env var
|
self._pg_psw_env_var_is_set = False # on win32, pg_dump need the PGPASSWORD env var
|
||||||
|
|
||||||
def dispatch(self, method, auth, params):
|
def dispatch(self, method, auth, params):
|
||||||
if method in [ 'create', 'get_progress', 'drop', 'dump',
|
if method in [ 'create', 'get_progress', 'drop', 'dump',
|
||||||
'restore', 'rename',
|
'restore', 'rename',
|
||||||
'change_admin_password', 'migrate_databases' ]:
|
'change_admin_password', 'migrate_databases' ]:
|
||||||
passwd = params[0]
|
passwd = params[0]
|
||||||
params = params[1:]
|
params = params[1:]
|
||||||
|
@ -64,7 +64,7 @@ class db(netsvc.ExportService):
|
||||||
raise KeyError("Method not found: %s" % method)
|
raise KeyError("Method not found: %s" % method)
|
||||||
fn = getattr(self, 'exp_'+method)
|
fn = getattr(self, 'exp_'+method)
|
||||||
return fn(*params)
|
return fn(*params)
|
||||||
|
|
||||||
def new_dispatch(self,method,auth,params):
|
def new_dispatch(self,method,auth,params):
|
||||||
pass
|
pass
|
||||||
def _create_empty_database(self, name):
|
def _create_empty_database(self, name):
|
||||||
|
@ -93,6 +93,7 @@ class db(netsvc.ExportService):
|
||||||
serv.actions[id]['progress'] = 0
|
serv.actions[id]['progress'] = 0
|
||||||
cr = sql_db.db_connect(db_name).cursor()
|
cr = sql_db.db_connect(db_name).cursor()
|
||||||
tools.init_db(cr)
|
tools.init_db(cr)
|
||||||
|
tools.config['lang'] = lang
|
||||||
cr.commit()
|
cr.commit()
|
||||||
cr.close()
|
cr.close()
|
||||||
cr = None
|
cr = None
|
||||||
|
@ -392,7 +393,7 @@ class common(_ObjectService):
|
||||||
security.check_super(passwd)
|
security.check_super(passwd)
|
||||||
else:
|
else:
|
||||||
raise Exception("Method not found: %s" % method)
|
raise Exception("Method not found: %s" % method)
|
||||||
|
|
||||||
fn = getattr(self, 'exp_'+method)
|
fn = getattr(self, 'exp_'+method)
|
||||||
return fn(*params)
|
return fn(*params)
|
||||||
|
|
||||||
|
@ -568,7 +569,7 @@ GNU Public Licence.
|
||||||
|
|
||||||
def exp_check_connectivity(self):
|
def exp_check_connectivity(self):
|
||||||
return bool(sql_db.db_connect('template1'))
|
return bool(sql_db.db_connect('template1'))
|
||||||
|
|
||||||
def exp_get_os_time(self):
|
def exp_get_os_time(self):
|
||||||
return os.times()
|
return os.times()
|
||||||
|
|
||||||
|
@ -598,7 +599,7 @@ class objects_proxy(netsvc.ExportService):
|
||||||
res = fn(db, uid, *params)
|
res = fn(db, uid, *params)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def new_dispatch(self,method,auth,params):
|
def new_dispatch(self,method,auth,params):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -634,7 +635,7 @@ class wizard(netsvc.ExportService):
|
||||||
fn = getattr(self, 'exp_'+method)
|
fn = getattr(self, 'exp_'+method)
|
||||||
res = fn(db, uid, *params)
|
res = fn(db, uid, *params)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def new_dispatch(self,method,auth,params):
|
def new_dispatch(self,method,auth,params):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -697,7 +698,7 @@ class report_spool(netsvc.ExportService):
|
||||||
res = fn(db, uid, *params)
|
res = fn(db, uid, *params)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def new_dispatch(self,method,auth,params):
|
def new_dispatch(self,method,auth,params):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -728,7 +729,7 @@ class report_spool(netsvc.ExportService):
|
||||||
self._reports[id]['format'] = format
|
self._reports[id]['format'] = format
|
||||||
self._reports[id]['state'] = True
|
self._reports[id]['state'] = True
|
||||||
except Exception, exception:
|
except Exception, exception:
|
||||||
|
|
||||||
tb = sys.exc_info()
|
tb = sys.exc_info()
|
||||||
tb_s = "".join(traceback.format_exception(*tb))
|
tb_s = "".join(traceback.format_exception(*tb))
|
||||||
logger = netsvc.Logger()
|
logger = netsvc.Logger()
|
||||||
|
|
|
@ -347,7 +347,7 @@ class TinyPoFile(object):
|
||||||
|
|
||||||
if name is None:
|
if name is None:
|
||||||
if not fuzzy:
|
if not fuzzy:
|
||||||
self.warn('Missing "#:" formated comment at line %d for the following source:\n\t%s',
|
self.warn('Missing "#:" formated comment at line %d for the following source:\n\t%s',
|
||||||
self.cur_line(), source[:30])
|
self.cur_line(), source[:30])
|
||||||
return self.next()
|
return self.next()
|
||||||
return type, name, res_id, source, trad
|
return type, name, res_id, source, trad
|
||||||
|
@ -541,9 +541,9 @@ def trans_generate(lang, modules, dbname=None):
|
||||||
|
|
||||||
query = 'SELECT name, model, res_id, module' \
|
query = 'SELECT name, model, res_id, module' \
|
||||||
' FROM ir_model_data'
|
' FROM ir_model_data'
|
||||||
|
|
||||||
query_models = """SELECT m.id, m.model, imd.module
|
query_models = """SELECT m.id, m.model, imd.module
|
||||||
FROM ir_model AS m, ir_model_data AS imd
|
FROM ir_model AS m, ir_model_data AS imd
|
||||||
WHERE m.id = imd.res_id AND imd.model = 'ir.model' """
|
WHERE m.id = imd.res_id AND imd.model = 'ir.model' """
|
||||||
|
|
||||||
if 'all_installed' in modules:
|
if 'all_installed' in modules:
|
||||||
|
@ -869,42 +869,7 @@ def trans_load_data(db_name, fileobj, fileformat, lang, lang_name=None, verbose=
|
||||||
|
|
||||||
if not ids:
|
if not ids:
|
||||||
# lets create the language with locale information
|
# lets create the language with locale information
|
||||||
fail = True
|
lang_obj.load_lang(cr, 1, lang=lang, lang_name=lang_name)
|
||||||
for ln in get_locales(lang):
|
|
||||||
try:
|
|
||||||
locale.setlocale(locale.LC_ALL, str(ln))
|
|
||||||
fail = False
|
|
||||||
break
|
|
||||||
except locale.Error:
|
|
||||||
continue
|
|
||||||
if fail:
|
|
||||||
lc = locale.getdefaultlocale()[0]
|
|
||||||
msg = 'Unable to get information for locale %s. Information from the default locale (%s) have been used.'
|
|
||||||
logger.warning(msg, lang, lc)
|
|
||||||
|
|
||||||
if not lang_name:
|
|
||||||
lang_name = tools.get_languages().get(lang, lang)
|
|
||||||
|
|
||||||
def fix_xa0(s):
|
|
||||||
if s == '\xa0':
|
|
||||||
return '\xc2\xa0'
|
|
||||||
return s
|
|
||||||
|
|
||||||
lang_info = {
|
|
||||||
'code': lang,
|
|
||||||
'iso_code': iso_lang,
|
|
||||||
'name': lang_name,
|
|
||||||
'translatable': 1,
|
|
||||||
'date_format' : str(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y')),
|
|
||||||
'time_format' : str(locale.nl_langinfo(locale.T_FMT)),
|
|
||||||
'decimal_point' : fix_xa0(str(locale.localeconv()['decimal_point'])),
|
|
||||||
'thousands_sep' : fix_xa0(str(locale.localeconv()['thousands_sep'])),
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
lang_obj.create(cr, uid, lang_info)
|
|
||||||
finally:
|
|
||||||
resetlocale()
|
|
||||||
|
|
||||||
|
|
||||||
# now, the serious things: we read the language file
|
# now, the serious things: we read the language file
|
||||||
|
|
Loading…
Reference in New Issue