Merge lp:~openerp-dev/openobject-server/6.0-opw-574351-nep into lp:openobject-server/6.0
- 6.0-opw-574351-nep
- Merge into 6.0
Proposed by
Nehal Panchal (OpenERP)
Status: | Rejected |
---|---|
Rejected by: | Naresh(OpenERP) |
Proposed branch: | lp:~openerp-dev/openobject-server/6.0-opw-574351-nep |
Merge into: | lp:openobject-server/6.0 |
Diff against target: |
430 lines (+195/-156) 3 files modified
bin/addons/base/ir/ir_values.py (+187/-154) bin/addons/base/security/base_security.xml (+7/-0) bin/addons/base/security/ir.model.access.csv (+1/-2) |
To merge this branch: | bzr merge lp:~openerp-dev/openobject-server/6.0-opw-574351-nep |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Naresh(OpenERP) (community) | Disapprove | ||
Review via email: mp+105194@code.launchpad.net |
Commit message
Description of the change
Hello,
Non-admin user cannot set default value with "only for you" option.
This fixes the issue.
Thanks.
To post a comment you must log in.
Unmerged revisions
- 3618. By Nehal Panchal (OpenERP)
-
[FIX] base : Non-admin user cannot set default value with 'only for you' option
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bin/addons/base/ir/ir_values.py' |
2 | --- bin/addons/base/ir/ir_values.py 2012-02-09 08:53:51 +0000 |
3 | +++ bin/addons/base/ir/ir_values.py 2012-05-09 12:18:18 +0000 |
4 | @@ -27,20 +27,28 @@ |
5 | EXCLUDED_FIELDS = set(( |
6 | 'report_sxw_content', 'report_rml_content', 'report_sxw', 'report_rml', |
7 | 'report_sxw_content_data', 'report_rml_content_data', 'search_view', )) |
8 | + |
9 | +ACTION_SLOTS = [ |
10 | + "client_action_multi", # sidebar wizard action |
11 | + "client_print_multi", # sidebar report printing button |
12 | + "client_action_relate", # sidebar related link |
13 | + "tree_but_open", # double-click on item in tree view |
14 | + "tree_but_action", # deprecated: same as tree_but_open |
15 | + ] |
16 | |
17 | class ir_values(osv.osv): |
18 | _name = 'ir.values' |
19 | |
20 | def _value_unpickle(self, cursor, user, ids, name, arg, context=None): |
21 | res = {} |
22 | - for report in self.browse(cursor, user, ids, context=context): |
23 | - value = report[name[:-9]] |
24 | - if not report.object and value: |
25 | + for record in self.browse(cursor, user, ids, context=context): |
26 | + value = record[name[:-9]] |
27 | + if record.key == 'default' and value: |
28 | try: |
29 | value = str(pickle.loads(value)) |
30 | - except: |
31 | + except Exception: |
32 | pass |
33 | - res[report.id] = value |
34 | + res[record.id] = value |
35 | return res |
36 | |
37 | def _value_pickle(self, cursor, user, id, name, value, arg, context=None): |
38 | @@ -49,18 +57,19 @@ |
39 | ctx = context.copy() |
40 | if self.CONCURRENCY_CHECK_FIELD in ctx: |
41 | del ctx[self.CONCURRENCY_CHECK_FIELD] |
42 | - if not self.browse(cursor, user, id, context=context).object: |
43 | + record = self.browse(cursor, user, id, context=context) |
44 | + if record.key == 'default': |
45 | value = pickle.dumps(value) |
46 | self.write(cursor, user, id, {name[:-9]: value}, context=ctx) |
47 | |
48 | - def onchange_object_id(self, cr, uid, ids, object_id, context={}): |
49 | + def onchange_object_id(self, cr, uid, ids, object_id, context=None): |
50 | if not object_id: return {} |
51 | act = self.pool.get('ir.model').browse(cr, uid, object_id, context=context) |
52 | return { |
53 | 'value': {'model': act.model} |
54 | } |
55 | |
56 | - def onchange_action_id(self, cr, uid, ids, action_id, context={}): |
57 | + def onchange_action_id(self, cr, uid, ids, action_id, context=None): |
58 | if not action_id: return {} |
59 | act = self.pool.get('ir.actions.actions').browse(cr, uid, action_id, context=context) |
60 | return { |
61 | @@ -68,29 +77,44 @@ |
62 | } |
63 | |
64 | _columns = { |
65 | - 'name': fields.char('Name', size=128), |
66 | - 'model_id': fields.many2one('ir.model', 'Object', size=128, |
67 | - help="This field is not used, it only helps you to select a good model."), |
68 | - 'model': fields.char('Object Name', size=128, select=True), |
69 | - 'action_id': fields.many2one('ir.actions.actions', 'Action', |
70 | - help="This field is not used, it only helps you to select the right action."), |
71 | - 'value': fields.text('Value'), |
72 | + 'name': fields.char('Name', size=128, required=True), |
73 | + 'model': fields.char('Model Name', size=128, select=True, required=True, |
74 | + help="Model to which this entry applies"), |
75 | + 'model_id': fields.many2one('ir.model', 'Model (change only)', size=128, |
76 | + help="Model to which this entry applies - " |
77 | + "helper field for setting a model, will " |
78 | + "automatically set the correct model name"), |
79 | + 'action_id': fields.many2one('ir.actions.actions', 'Action (change only)', |
80 | + help="Action bound to this entry - " |
81 | + "helper field for binding an action, will " |
82 | + "automatically set the correct reference"), |
83 | + 'value': fields.text('Value', help="Default value (pickled) or reference to an action"), |
84 | 'value_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle, |
85 | - method=True, type='text', string='Value'), |
86 | - 'object': fields.boolean('Is Object'), |
87 | - 'key': fields.selection([('action','Action'),('default','Default')], 'Type', size=128, select=True), |
88 | - 'key2' : fields.char('Event Type',help="The kind of action or button in the client side that will trigger the action.", size=128, select=True), |
89 | - 'meta': fields.text('Meta Datas'), |
90 | - 'meta_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle, |
91 | - method=True, type='text', string='Metadata'), |
92 | - 'res_id': fields.integer('Object ID', help="Keep 0 if the action must appear on all resources.", select=True), |
93 | - 'user_id': fields.many2one('res.users', 'User', ondelete='cascade', select=True), |
94 | - 'company_id': fields.many2one('res.company', 'Company', select=True) |
95 | + type='text', |
96 | + string='Default value or action reference'), |
97 | + 'key': fields.selection([('action','Action'),('default','Default')], |
98 | + 'Type', size=128, select=True, required=True, |
99 | + help="- Action: an action attached to one slot of the given model\n" |
100 | + "- Default: a default value for a model field"), |
101 | + 'key2' : fields.char('Qualifier', size=128, select=True, |
102 | + help="For actions, one of the possible action slots: \n" |
103 | + " - client_action_multi\n" |
104 | + " - client_print_multi\n" |
105 | + " - client_action_relate\n" |
106 | + " - tree_but_open\n" |
107 | + "For defaults, an optional condition" |
108 | + ,), |
109 | + 'res_id': fields.integer('Record ID', select=True, |
110 | + help="Database identifier of the record to which this applies. " |
111 | + "0 = for all records"), |
112 | + 'user_id': fields.many2one('res.users', 'User', ondelete='cascade', select=True, |
113 | + help="If set, action binding only applies for this user."), |
114 | + 'company_id': fields.many2one('res.company', 'Company', ondelete='cascade', select=True, |
115 | + help="If set, action binding only applies for this company") |
116 | } |
117 | _defaults = { |
118 | - 'key': lambda *a: 'action', |
119 | - 'key2': lambda *a: 'tree_but_open', |
120 | - 'company_id': lambda *a: False |
121 | + 'key': 'action', |
122 | + 'key2': 'tree_but_open', |
123 | } |
124 | |
125 | def _auto_init(self, cr, context=None): |
126 | @@ -99,137 +123,146 @@ |
127 | if not cr.fetchone(): |
128 | cr.execute('CREATE INDEX ir_values_key_model_key2_res_id_user_id_idx ON ir_values (key, model, key2, res_id, user_id)') |
129 | |
130 | - def set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=False, preserve_user=False, company=False): |
131 | + def set_default(self, cr, uid, model, field_name, value, for_all_users=True, company_id=False, condition=False): |
132 | if isinstance(value, unicode): |
133 | value = value.encode('utf8') |
134 | - if not isobject: |
135 | - value = pickle.dumps(value) |
136 | - if meta: |
137 | - meta = pickle.dumps(meta) |
138 | - assert isinstance(models, (list, tuple)), models |
139 | - assert not company or isinstance(company, int), "Parameter 'company' must be an integer (company ID)!" |
140 | - if company and company is True: |
141 | - current_user_obj = self.pool.get('res.users').browse(cr, uid, uid, context={}) |
142 | - company = current_user_obj.company_id.id |
143 | - |
144 | - ids_res = [] |
145 | - for model in models: |
146 | + if company_id is True: |
147 | + user = self.pool.get('res.users').browse(cr, uid, uid) |
148 | + company_id = user.company_id.id |
149 | + search_criteria = [ |
150 | + ('key', '=', 'default'), |
151 | + ('key2', '=', condition and condition[:200]), |
152 | + ('model', '=', model), |
153 | + ('name', '=', field_name), |
154 | + ('user_id', '=', False if for_all_users else uid), |
155 | + ('company_id','=', company_id) |
156 | + ] |
157 | + self.unlink(cr, uid, self.search(cr, uid, search_criteria)) |
158 | + return self.create(cr, uid, { |
159 | + 'name': field_name, |
160 | + 'value': pickle.dumps(value), |
161 | + 'model': model, |
162 | + 'key': 'default', |
163 | + 'key2': condition and condition[:200], |
164 | + 'user_id': False if for_all_users else uid, |
165 | + 'company_id': company_id, |
166 | + }) |
167 | + |
168 | + def get_defaults(self, cr, uid, model, condition=False): |
169 | + query = """SELECT v.id, v.name, v.value FROM ir_values v |
170 | + LEFT JOIN res_users u ON (v.user_id = u.id) |
171 | + WHERE v.key = %%s AND v.model = %%s |
172 | + AND (v.user_id = %%s OR v.user_id IS NULL) |
173 | + AND (v.company_id IS NULL OR |
174 | + v.company_id = |
175 | + (SELECT company_id from res_users where id = %%s) |
176 | + ) |
177 | + %s |
178 | + ORDER BY v.user_id, u.company_id""" |
179 | + query = query % ('AND v.key2 = %s' if condition else '') |
180 | + params = ('default', model, uid, uid) |
181 | + if condition: |
182 | + params += (condition[:200],) |
183 | + cr.execute(query, params) |
184 | + defaults = {} |
185 | + for row in cr.dictfetchall(): |
186 | + defaults.setdefault(row['name'], |
187 | + (row['id'], row['name'], pickle.loads(row['value'].encode('utf-8')))) |
188 | + return defaults.values() |
189 | + |
190 | + def set_action(self, cr, uid, name, action_slot, model, action, res_id=False): |
191 | + assert isinstance(action, basestring) and ',' in action, \ |
192 | + 'Action definition must be an action reference, e.g. "ir.actions.act_window,42"' |
193 | + assert action_slot in ACTION_SLOTS, \ |
194 | + 'Action slot (%s) must be one of: %r' % (action_slot, ACTION_SLOTS) |
195 | + search_criteria = [ |
196 | + ('key', '=', 'action'), |
197 | + ('key2', '=', action_slot), |
198 | + ('model', '=', model), |
199 | + ('res_id', '=', res_id or 0), # int field -> NULL == 0 |
200 | + ('value', '=', action), |
201 | + ] |
202 | + self.unlink(cr, uid, self.search(cr, uid, search_criteria)) |
203 | + return self.create(cr, uid, { |
204 | + 'key': 'action', |
205 | + 'key2': action_slot, |
206 | + 'model': model, |
207 | + 'res_id': res_id, |
208 | + 'name': name, |
209 | + 'value': action, |
210 | + }) |
211 | + |
212 | + def get_actions(self, cr, uid, action_slot, model, res_id=False, context=None): |
213 | + assert action_slot in ACTION_SLOTS, 'Illegal action slot value: %s' % action_slot |
214 | + query = """SELECT v.id, v.name, v.value FROM ir_values v |
215 | + WHERE v.key = %s AND v.key2 = %s |
216 | + AND v.model = %s |
217 | + AND (v.res_id = %s |
218 | + OR v.res_id IS NULL |
219 | + OR v.res_id = 0) |
220 | + ORDER BY v.id""" |
221 | + cr.execute(query, ('action', action_slot, model, res_id or None)) |
222 | + results = {} |
223 | + for action in cr.dictfetchall(): |
224 | + action_model,id = action['value'].split(',') |
225 | + fields = [ |
226 | + field |
227 | + for field in self.pool.get(action_model)._all_columns |
228 | + if field not in EXCLUDED_FIELDS] |
229 | + try: |
230 | + action_def = self.pool.get(action_model).read(cr, uid, int(id), fields, context) |
231 | + if action_def: |
232 | + if action_model in ('ir.actions.report.xml','ir.actions.act_window', |
233 | + 'ir.actions.wizard'): |
234 | + groups = action_def.get('groups_id') |
235 | + if groups: |
236 | + cr.execute('SELECT 1 FROM res_groups_users_rel WHERE gid IN %s AND uid=%s', |
237 | + (tuple(groups), uid)) |
238 | + if not cr.fetchone(): |
239 | + if action['name'] == 'Menuitem': |
240 | + raise osv.except_osv('Error !', |
241 | + 'You do not have the permission to perform this operation !!!') |
242 | + continue |
243 | + results[action['name']] = (action['id'], action['name'], action_def) |
244 | + except except_orm, e: |
245 | + continue |
246 | + return results.values() |
247 | + |
248 | + def _map_legacy_model_list(self, model_list, map_fn, merge_results=False): |
249 | + assert isinstance(model_list, (list, tuple)), \ |
250 | + "model_list should be in the form [model,..] or [(model,res_id), ..]" |
251 | + results = [] |
252 | + for model in model_list: |
253 | + res_id = False |
254 | if isinstance(model, (list, tuple)): |
255 | - model,res_id = model |
256 | + model, res_id = model |
257 | + result = map_fn(model, res_id) |
258 | + if merge_results: |
259 | + results.extend(result) |
260 | else: |
261 | - res_id=False |
262 | - if replace: |
263 | - search_criteria = [ |
264 | - ('key', '=', key), |
265 | - ('key2', '=', key2), |
266 | - ('model', '=', model), |
267 | - ('res_id', '=', res_id), |
268 | - ('user_id', '=', preserve_user and uid), |
269 | - ('company_id' ,'=', company) |
270 | - |
271 | - ] |
272 | - if key in ('meta', 'default'): |
273 | - search_criteria.append(('name', '=', name)) |
274 | - else: |
275 | - search_criteria.append(('value', '=', value)) |
276 | + results.append(result) |
277 | + return results |
278 | |
279 | - self.unlink(cr, uid, self.search(cr, uid, search_criteria)) |
280 | - vals = { |
281 | - 'name': name, |
282 | - 'value': value, |
283 | - 'model': model, |
284 | - 'object': isobject, |
285 | - 'key': key, |
286 | - 'key2': key2 and key2[:200], |
287 | - 'meta': meta, |
288 | - 'user_id': preserve_user and uid, |
289 | - 'company_id':company |
290 | - } |
291 | - if res_id: |
292 | - vals['res_id'] = res_id |
293 | - ids_res.append(self.create(cr, uid, vals)) |
294 | - return ids_res |
295 | + def set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=False, preserve_user=False, company=False): |
296 | + assert key in ['default', 'action'], "ir.values entry keys must be in ['default','action']" |
297 | + if key == 'default': |
298 | + def do_set(model,res_id): |
299 | + return self.set_default(cr, uid, model, field_name=name, value=value, |
300 | + for_all_users=(not preserve_user), company_id=company, |
301 | + condition=key2) |
302 | + elif key == 'action': |
303 | + def do_set(model,res_id): |
304 | + return self.set_action(cr, uid, name, action_slot=key2, model=model, action=value, res_id=res_id) |
305 | + return self._map_legacy_model_list(models, do_set) |
306 | |
307 | def get(self, cr, uid, key, key2, models, meta=False, context={}, res_id_req=False, without_user=True, key2_req=True): |
308 | - result = [] |
309 | - for m in models: |
310 | - if isinstance(m, (list, tuple)): |
311 | - m, res_id = m |
312 | - else: |
313 | - res_id=False |
314 | - |
315 | - where = ['key=%s','model=%s'] |
316 | - params = [key, str(m)] |
317 | - if key2: |
318 | - where.append('key2=%s') |
319 | - params.append(key2[:200]) |
320 | - elif key2_req and not meta: |
321 | - where.append('key2 is null') |
322 | - if res_id_req and (models[-1][0]==m): |
323 | - if res_id: |
324 | - where.append('res_id=%s') |
325 | - params.append(res_id) |
326 | - else: |
327 | - where.append('(res_id is NULL)') |
328 | - elif res_id: |
329 | - if (models[-1][0]==m): |
330 | - where.append('(res_id=%s or (res_id is null))') |
331 | - params.append(res_id) |
332 | - else: |
333 | - where.append('res_id=%s') |
334 | - params.append(res_id) |
335 | - |
336 | - order = 'id, company_id' |
337 | - where.append('''(user_id=%s or (user_id IS NULL)) |
338 | - and (company_id is null or |
339 | - company_id = (SELECT company_id FROM res_users WHERE id = %s)) order by '''+ order) |
340 | - params += [uid, uid] |
341 | - clause = ' and '.join(where) |
342 | - cr.execute('select id,name,value,object,meta, key from ir_values where ' + clause, params) |
343 | - result = cr.fetchall() |
344 | - if result: |
345 | - break |
346 | - |
347 | - if not result: |
348 | - return [] |
349 | - |
350 | - def _result_get(x, keys): |
351 | - if x[1] in keys: |
352 | - return False |
353 | - keys.append(x[1]) |
354 | - if x[3]: |
355 | - model,id = x[2].split(',') |
356 | - # FIXME: It might be a good idea to opt-in that kind of stuff |
357 | - # FIXME: instead of arbitrarily removing random fields |
358 | - fields = [ |
359 | - field |
360 | - for field in self.pool.get(model).fields_get_keys(cr, uid) |
361 | - if field not in EXCLUDED_FIELDS] |
362 | - |
363 | - try: |
364 | - datas = self.pool.get(model).read(cr, uid, [int(id)], fields, context) |
365 | - except except_orm, e: |
366 | - return False |
367 | - datas = datas and datas[0] |
368 | - if not datas: |
369 | - return False |
370 | - else: |
371 | - datas = pickle.loads(x[2].encode('utf-8')) |
372 | - if meta: |
373 | - return (x[0], x[1], datas, pickle.loads(x[4])) |
374 | - return (x[0], x[1], datas) |
375 | - keys = [] |
376 | - res = filter(None, map(lambda x: _result_get(x, keys), result)) |
377 | - res2 = res[:] |
378 | - for r in res: |
379 | - if isinstance(r[2], dict) and r[2].get('type') in ('ir.actions.report.xml','ir.actions.act_window','ir.actions.wizard'): |
380 | - groups = r[2].get('groups_id') |
381 | - if groups: |
382 | - cr.execute('SELECT COUNT(1) FROM res_groups_users_rel WHERE gid IN %s AND uid=%s',(tuple(groups), uid)) |
383 | - cnt = cr.fetchone()[0] |
384 | - if not cnt: |
385 | - res2.remove(r) |
386 | - if r[1] == 'Menuitem' and not res2: |
387 | - raise osv.except_osv('Error !','You do not have the permission to perform this operation !!!') |
388 | - return res2 |
389 | + assert key in ['default', 'action'], "ir.values entry keys must be in ['default','action']" |
390 | + if key == 'default': |
391 | + def do_get(model,res_id): |
392 | + return self.get_defaults(cr, uid, model, condition=key2) |
393 | + elif key == 'action': |
394 | + def do_get(model,res_id): |
395 | + return self.get_actions(cr, uid, action_slot=key2, model=model, res_id=res_id, context=context) |
396 | + return self._map_legacy_model_list(models, do_get, merge_results=True) |
397 | + |
398 | ir_values() |
399 | |
400 | === modified file 'bin/addons/base/security/base_security.xml' |
401 | --- bin/addons/base/security/base_security.xml 2011-03-03 15:59:18 +0000 |
402 | +++ bin/addons/base/security/base_security.xml 2012-05-09 12:18:18 +0000 |
403 | @@ -62,6 +62,13 @@ |
404 | <field name="global" eval="True"/> |
405 | <field name="domain_force">[('company_id','child_of',[user.company_id.id])]</field> |
406 | </record> |
407 | + |
408 | + <record model="ir.rule" id="ir_values_default_rule"> |
409 | + <field name="name">Defaults: alter personal values only</field> |
410 | + <field name="model_id" ref="model_ir_values"/> |
411 | + <field name="domain_force">[('key','=','default'),('user_id','=',user.id)]</field> |
412 | + <field name="perm_read" eval="False"/> |
413 | + </record> |
414 | |
415 | </data> |
416 | </openerp> |
417 | |
418 | === modified file 'bin/addons/base/security/ir.model.access.csv' |
419 | --- bin/addons/base/security/ir.model.access.csv 2011-02-23 15:58:33 +0000 |
420 | +++ bin/addons/base/security/ir.model.access.csv 2012-05-09 12:18:18 +0000 |
421 | @@ -38,8 +38,7 @@ |
422 | "access_ir_ui_view_custom_group_user","ir_ui_view_custom_group_user","model_ir_ui_view_custom",,1,0,0,0 |
423 | "access_ir_ui_view_custom_group_system","ir_ui_view_custom_group_system","model_ir_ui_view_custom","group_system",1,1,1,1 |
424 | "access_ir_ui_view_sc_group_user","ir_ui_view_sc group_user","model_ir_ui_view_sc",,1,1,1,1 |
425 | -"access_ir_values_group_erp_manager","ir_values group_erp_manager","model_ir_values","group_erp_manager",1,1,1,1 |
426 | -"access_ir_values_group_all","ir_values group_all","model_ir_values",,1,0,1,0 |
427 | +"access_ir_values_group_all","ir_values group_all","model_ir_values",,1,1,1,1 |
428 | "access_res_company_group_erp_manager","res_company group_erp_manager","model_res_company","group_erp_manager",1,1,1,1 |
429 | "access_res_company_group_user","res_company group_user","model_res_company",,1,0,0,0 |
430 | "access_res_country_group_all","res_country group_user_all","model_res_country",,1,0,0,0 |
Hello
The changes are huge and very risky to be merged to stable version. This may cause regression and effect the existing customers. I would reject this merge proposal.
Thanks,