[IMP] share:
[odoo/odoo.git] / addons / share / wizard / share_wizard.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 ##############################################################################
21 from osv import osv, fields
22 from tools.translate import _
23 import tools
24
25 def _generate_random_number():
26    import random
27    RANDOM_PASS_CHARACTERS = [chr(x) for x in range(48,58) + range(97,123) + range(65,91)]
28    RANDOM_PASS_CHARACTERS.remove('l') #lowercase l, easily mistaken as one or capital i
29    RANDOM_PASS_CHARACTERS.remove('I') #uppercase i, easily mistaken as one or lowercase l
30    RANDOM_PASS_CHARACTERS.remove('O') #uppercase o, mistaken with zero
31    RANDOM_PASS_CHARACTERS.remove('o') #lowercase o, mistaken with zero
32    RANDOM_PASS_CHARACTERS.remove('0') #zero, mistaken with o-letter
33    def generate_random_pass():
34        pass_chars = RANDOM_PASS_CHARACTERS[:]
35        random.shuffle(pass_chars)
36        return ''.join(pass_chars[0:10])
37    return generate_random_pass()
38
39 class share_create(osv.osv_memory):
40     _name = 'share.create'
41     _description = 'Create share'
42
43     def _access(self, cr, uid, ids, field_name, arg, context=None):
44         if context is None:
45             context = {}
46         res = {}
47         action_id = context.get('action_id', False)
48         access_obj = self.pool.get('ir.model.access')
49         action_obj = self.pool.get('ir.actions.act_window')
50         model_obj = self.pool.get('ir.model')
51         user_obj = self.pool.get('res.users')
52         current_user = user_obj.browse(cr, uid, uid)
53         access_ids = []
54         if action_id:
55             action = action_obj.browse(cr, uid, action_id, context=context)
56             active_model_ids = model_obj.search(cr, uid, [('model','=',action.res_model)])
57             active_model_id = active_model_ids and active_model_ids[0] or False
58             access_ids = access_obj.search(cr, uid, [
59                     ('group_id','in',map(lambda x:x.id, current_user.groups_id)),
60                     ('model_id','',active_model_id)])
61         for rec_id in ids:
62             write_access = False
63             read_access = False
64             for access in access_obj.browse(cr, uid, access_ids, context=context):
65                 if access.perm_write:
66                     write_access = True
67                 if access.perm_read:
68                     read_access = True
69             res[rec_id]['write_access'] = write_access
70             res[rec_id]['read_access'] = read_access          
71         return res
72
73     _columns = {
74         'action_id': fields.many2one('ir.actions.act_window', 'Action', required=True),
75         'domain': fields.char('Domain', size=64),
76         'user_type': fields.selection( [ ('existing','Existing'),('new','New')],'User Type'),
77         'user_ids': fields.many2many('res.users', 'share_user_rel', 'share_id','user_id', 'Share Users'),
78         'new_user': fields.text("New user"),
79         'access_mode': fields.selection([('readwrite','READ & WRITE'),('readonly','READ ONLY')],'Access Mode'),
80         'write_access': fields.function(_access, method=True, string='Write Access',type='boolean', multi='write_access'),
81         'read_access': fields.function(_access, method=True, string='Write Access',type='boolean', multi='read_access'),
82     }
83     _defaults = {
84         'user_type' : 'existing',
85         'domain': '[]',
86         'access_mode': 'readonly'
87         
88     }
89
90     def default_get(self, cr, uid, fields, context=None):
91         """ 
92              To get default values for the object.
93         """ 
94
95         res = super(share_create, self).default_get(cr, uid, fields, context=context)               
96         if not context:
97             context={}
98         action_id = context.get('action_id', False)
99         domain = context.get('domain', '[]')  
100        
101                    
102         if 'action_id' in fields:
103             res['action_id'] = action_id
104         if 'domain' in fields:
105             res['domain'] = domain                             
106         return res
107
108     def do_step_1(self, cr, uid, ids, context=None):
109         """
110         This action to excute step 1
111        
112         """
113         if not context:
114             context = {}
115
116         data_obj = self.pool.get('ir.model.data')               
117         
118         step1_form_view = data_obj._get_id(cr, uid, 'share', 'share_step1_form')
119         
120         if step1_form_view:
121             step1_form_view_id = data_obj.browse(cr, uid, step1_form_view, context=context).res_id        
122
123         step1_id = False
124         for this in self.browse(cr, uid, ids, context=context):
125             vals ={
126                 'domain': this.domain, 
127                 'action_id': this.action_id and this.action_id.id or False,
128             }   
129             step1_id = this.id        
130
131         context.update(vals)
132         value = {
133             'name': _('Step:2 Sharing Wizard'), 
134             'view_type': 'form', 
135             'view_mode': 'form', 
136             'res_model': 'share.create',            
137             'view_id': False,
138             'res_id': step1_id, 
139             'views': [(step1_form_view_id, 'form'), (False, 'tree'), (False, 'calendar'), (False, 'graph')], 
140             'type': 'ir.actions.act_window', 
141             'context': context,
142             'target': 'new'
143         }
144         return value
145
146
147     def do_step_2(self, cr, uid, ids, context=None):
148         """
149         This action to excute step 2
150        
151         """
152         if not context:
153             context = {}
154
155         data_obj = self.pool.get('ir.model.data')               
156         
157         step2_form_view = data_obj._get_id(cr, uid, 'share', 'share_step2_form')
158         
159         if step2_form_view:
160             step2_form_view_id = data_obj.browse(cr, uid, step2_form_view, context=context).res_id        
161
162         step1_id = False
163         for this in self.browse(cr, uid, ids, context=context):
164             vals ={
165                 'user_type': this.user_type, 
166                 'existing_user_ids': map(lambda x:x.id, this.user_ids),
167                 'new_user': this.new_user,
168             }           
169
170         context.update(vals)
171         value = {
172             'name': _('Step:3 Sharing Wizard'), 
173             'view_type': 'form', 
174             'view_mode': 'form', 
175             'res_model': 'share.create',            
176             'view_id': False, 
177             'views': [(step2_form_view_id, 'form'), (False, 'tree'), (False, 'calendar'), (False, 'graph')], 
178             'type': 'ir.actions.act_window', 
179             'context': context,
180             'target': 'new'
181         }
182         return value
183
184
185     def do_step_3(self, cr, uid, ids, context=None):
186         """
187         This action to excute step 3
188        
189         """
190         if not context:
191             context = {}
192
193         for this in self.browse(cr, uid, ids, context=context):            
194             vals ={
195                 'access_mode': this.access_mode,
196             }           
197
198         context.update(vals)
199         
200         group_obj = self.pool.get('res.groups')
201         user_obj = self.pool.get('res.users')
202         fields_obj = self.pool.get('ir.model.fields') 
203         model_access_obj = self.pool.get('ir.model.access')            
204         model_obj = self.pool.get('ir.model')
205         rule_obj = self.pool.get('ir.rule')
206         action_obj = self.pool.get('ir.actions.act_window')        
207
208         new_users = context.get('new_user', False)
209         action_id = context.get('action_id', False)
210         user_type = context.get('user_type', False)
211         access_mode = context.get('access_mode', False)
212         action = action_obj.browse(cr, uid, action_id, context=context)
213         active_model = action.res_model            
214         
215         active_id = False #TODO: Pass record id of res_model of action
216         existing_user_ids = context.get('existing_user_ids', False)
217         domain = eval(context.get('domain', '[]'))
218
219         # Create Share Group
220         share_group_name = '%s: %s' %('Sharing', active_model)
221         group_ids = group_obj.search(cr, uid, [('name','=',share_group_name)])
222         group_id = group_ids and group_ids[0] or False
223         if not group_id:
224             group_id = group_obj.create(cr, uid, {'name': share_group_name, 'share': True})
225         else:
226             group = group_obj.browse(cr, uid, group_id, context=context)
227             if not group.share:
228                 raise osv.except_osv(_('Error'), _("Share Group is exits without sharing !"))        
229         
230         # Create new user       
231               
232         current_user = user_obj.browse(cr, uid, uid)
233         user_ids = []
234         if user_type == 'new' and new_users:
235             for new_user in new_users.split('\n'):
236                 password = _generate_random_number()
237                 user_id = user_obj.create(cr, uid, {
238                         'login': new_user,
239                         'password': password,
240                         'name': new_user,
241                         'user_email': new_user,
242                         'groups_id': [(6,0,[group_id])],
243                         'action_id': action_id,
244                         'share': True,
245                         'company_id': current_user.company_id and current_user.company_id.id})
246                 user_ids.append(user_id)
247             context['new_user_ids'] = user_ids
248
249         # Modify existing user
250         if user_type == 'existing':                         
251             user_obj.write(cr, uid, existing_user_ids , {
252                                    'groups_id': [(4,group_id)],
253                                    'action_id': action_id
254                             })
255         
256
257         #ACCESS RIGHTS / IR.RULES COMPUTATION 
258            
259         active_model_ids = model_obj.search(cr, uid, [('model','=',active_model)])
260         active_model_id = active_model_ids and active_model_ids[0] or False
261         
262         def _get_relation(model_id, ttypes, new_obj=[]):            
263             obj = []            
264             models = map(lambda x:x[1].model, new_obj)
265             field_ids = fields_obj.search(cr, uid, [('model_id','=',model_id),('ttype','in', ttypes)])          
266             for field in fields_obj.browse(cr, uid, field_ids, context=context):
267                 if field.relation not in models:
268                     relation_model_ids = model_obj.search(cr, uid, [('model','=',field.relation)])
269                     relation_model_id = relation_model_ids and relation_model_ids[0] or False
270                     relation_model = model_obj.browse(cr, uid, relation_model_id, context=context)
271                     obj.append((field.relation_field, relation_model))
272
273                     if relation_model_id != model_id and field.ttype in ['one2many', 'many2many']:
274                         obj += _get_relation(relation_model_id, [field.ttype], obj) 
275                 
276             return obj
277
278         active_model = model_obj.browse(cr, uid, active_model_id, context=context)
279         obj0 = [(None, active_model)]
280         obj1 = _get_relation(active_model_id, ['one2many'])
281         obj2 = _get_relation(active_model_id, ['one2many', 'many2many'])
282         obj3 = _get_relation(active_model_id, ['many2one'])
283         for rel_field, model in obj1:
284             obj3 += _get_relation(model.id, ['many2one'])
285
286         current_user = user_obj.browse(cr, uid, uid, context=context)
287         if access_mode == 'readonly':
288             res = []
289             # intersect with read access rights of user running the 
290             # wizard, to avoid adding more access than current
291             for group in current_user.groups_id:
292                 for access_control in group.model_access:
293                      if access_control.model_id.id in res:
294                         continue
295                      if access_control.perm_read:
296                         res.append(access_control.model_id.id)
297                         model_access_obj.create(cr, uid, {
298                         'name': 'Read Access of group %s on %s model'%(share_group_name, access_control.model_id.name),
299                         'model_id' : access_control.model_id.id,
300                         'group_id' : group_id,
301                         'perm_read' : True
302                         })    
303             res = []
304             for rel_field, model in obj0+obj1+obj2+obj3:
305                 if model.id in res:
306                     continue
307                 res.append(model.id)
308                 model_access_obj.create(cr, uid, {
309                         'name': 'Read Access of group %s on %s model'%(share_group_name, model.name),
310                         'model_id' : model.id,
311                         'group_id' : group_id,
312                         'perm_read' : True
313                         })
314         if access_mode == 'readwrite':
315             res = []
316             for rel_field, model in obj0+obj1:
317                 if model.id in res:
318                     continue
319                 res.append(model.id)
320                 model_access_obj.create(cr, uid, {
321                         'name': 'Write Access of group %s on %s model'%(share_group_name, model.name),
322                         'model_id' : model.id,
323                         'group_id' : group_id,
324                         'perm_read' : True,
325                         'perm_write' : True,
326                         'perm_unlink' : True,
327                         'perm_create' : True,
328                         })
329             # intersect with access rights of user 
330             # running the wizard, to avoid adding more access than current
331
332             for group in current_user.groups_id:
333                 for access_control in group.model_access:
334                      if access_control.model_id.id in res:
335                         continue
336                      if access_control.perm_read:
337                         res.append(access_control.model_id.id)
338                         model_access_obj.create(cr, uid, {
339                         'name': 'Read Access of group %s on %s model'%(share_group_name, access_control.model_id.name),
340                         'model_id' : access_control.model_id.id,
341                         'group_id' : group_id,
342                         'perm_read' : True
343                         })
344             for rel_field, model in obj2+obj3:
345                 if model.id in res:
346                     continue
347                 res.append(model.id)
348                 model_access_obj.create(cr, uid, {
349                         'name': 'Read Access of group %s on %s model'%(share_group_name, model.name),
350                         'model_id' : model.id,
351                         'group_id' : group_id,
352                         'perm_read' : True
353                         })
354         # 
355         # And on OBJ0, OBJ1, OBJ2, OBJ3: add all rules from groups of the user
356         #  that is sharing in the many2many of the rules on the new group 
357         #  (rule must be copied instead of adding it if it contains a reference to uid
358         #  or user.xxx so it can be replaced correctly)
359
360         for group in current_user.groups_id:
361             res = []
362             for rel_field, model in obj0+obj1+obj2+obj3:
363                 if model.id in res:
364                     continue
365                 res.append(model.id)
366                 for rule in group.rule_groups:
367                     if rule.model_id == model.id:                 
368                         rule_obj.copy(cr, uid, rule.id, default={
369                         'name': '%s-%s'%(share_group_name, model.model), 
370                         'groups': [(6,0,[group_id])]}, context=context)
371
372         rule_obj.create(cr, uid, {
373                 'name': '%s-%s'%(share_group_name, active_model.model),
374                 'model_id': active_model.id,
375                 'domain_force': domain,
376                 'groups': [(6,0,[group_id])]
377             })
378         for rel_field, model in obj1:
379             obj1_domain = []
380             for opr1, opt, opr2 in domain:
381                 new_opr1 = '%s.%s'%(rel_field, opr1)
382                 obj1_domain.append((new_opr1, opt, opr2))
383
384             rule_obj.create(cr, uid, {
385                 'name': '%s-%s'%(share_group_name, model.model),
386                 'model_id': model.id,
387                 'domain_force': obj1_domain,
388                 'groups': [(6,0,[group_id])]
389             })
390         context['share_model'] = active_model.model
391         context['share_rec_id'] = active_id
392
393         
394         data_obj = self.pool.get('ir.model.data')               
395         
396         form_view = data_obj._get_id(cr, uid, 'share', 'share_result_form')
397         form_view_id = False
398         if form_view:
399             form_view_id = data_obj.browse(cr, uid, form_view, context=context).res_id        
400
401       
402         value = {
403             'name': _('Step:4 Share Users Detail'), 
404             'view_type': 'form', 
405             'view_mode': 'form', 
406             'res_model': 'share.result',            
407             'view_id': False, 
408             'views': [(form_view_id, 'form'), (False, 'tree'), (False, 'calendar'), (False, 'graph')], 
409             'type': 'ir.actions.act_window', 
410             'context': context,
411             'target': 'new'
412         }
413         return value
414 share_create()
415
416
417 class share_result(osv.osv_memory):
418     _name = "share.result"    
419     _columns = {
420         'users': fields.text("Users", readonly=True),               
421      }
422
423     
424
425     def do_send_email(self, cr, uid, ids, context=None):        
426         user_obj = self.pool.get('res.users')        
427         if not context:
428             context={}
429         existing_user_ids = context.get('existing_user_ids', [])
430         new_user_ids = context.get('new_user_ids', [])  
431         share_url = tools.config.get('share_root_url', False)
432         user = user_obj.browse(cr, uid, uid, context=context)
433         for share_user in user_obj.browse(cr, uid, new_user_ids+existing_user_ids, context=context):
434             email_to = share_user.user_email
435             subject = '%s wants to share private data with you' %(user.name)
436             body = """
437     Dear,
438
439              %s wants to share private data from OpenERP with you! 
440     """%(user.name)
441             if share_url:
442                 body += """
443              To view it, you can access the following URL:
444                    %s
445     """%(user.name, share_url)       
446             if share_user.id in new_user_ids:
447                 body += """
448              You may use the following login and password to get access to this
449              protected area:
450                    login: %s
451                    password: %s
452     """%(user.login, user.password)
453             elif share_user.id in existing_user_ids:
454                  body += """
455              You may use your existing login and password to get access to this
456              additional data. As a reminder, your login is %s.
457     """%(user.name) 
458
459             flag = tools.email_send(
460                 user.user_email,
461                 email_to,
462                 subject,
463                 body                
464             )
465         return flag
466
467     
468     def default_get(self, cr, uid, fields, context=None):
469         """ 
470              To get default values for the object.
471         """ 
472
473         res = super(share_result, self).default_get(cr, uid, fields, context=context)
474         user_obj = self.pool.get('res.users')        
475         if not context:
476             context={}
477         existing_user_ids = context.get('existing_user_ids', [])
478         new_user_ids = context.get('new_user_ids', [])  
479         share_url = tools.config.get('share_root_url', False)
480         if 'users' in fields:
481             users = []
482             for user in user_obj.browse(cr, uid, new_user_ids):
483                 txt = 'Login: %s Password: %s' %(user.login, user.password)
484                 if share_url:
485                     txt += ' Share URL: %s' %(share_url)
486                 users.append(txt)            
487             for user in user_obj.browse(cr, uid, existing_user_ids):            
488                 txt = 'Login: %s' %(user.login)
489                 if share_url:
490                     txt += ' Share URL: %s' %(share_url)
491                 users.append(txt)
492             res['users'] = '\n'.join(users)
493         return res
494  
495 share_result()