~unifield-team/unifield-wm/us-826

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#!/usr/bin/env python
# -*- encoding: utf-8 -*-

from osv import osv
from osv import fields
from osv import orm
from lxml import etree
import logging

class ir_ui_view(osv.osv):
    """
    Inherit the ir.ui.view model to delete button access rules when deleting a view
    and add button access rules tab and reparse view tab to view
    """

    _inherit = "ir.ui.view"
    
    def _get_button_access_rules(self, cr, uid, ids, field_name, arg, context):
        res = dict.fromkeys(ids)
        records = self.browse(cr, 1, ids)
        pool = self.pool.get('msf_button_access_rights.button_access_rule')
        for record in records:
            search = pool.search(cr, 1, [('view_id','=',record.id)])
            res[record.id] = search
        return res

    _columns = {
        'button_access_rules_ref': fields.function(_get_button_access_rules, type='one2many', obj='msf_button_access_rights.button_access_rule', method=True, string='Button Access Rules'),
    }

    def generate_button_access_rules(self, cr, uid, view_id, context=None):
        """
        Called by create method of ir.model.data after xml id is created for a view.
        This method generates the first set of button access rules for a new view.
        """
        view = self.browse(cr, 1, view_id)
        model_id = self.pool.get('ir.model').search(cr, 1, [('model','=',view.model)])
        buttons = None

        if model_id:
            try:
                buttons = self.parse_view(view.arch, model_id[0], view_id)
            except (ValueError, etree.XMLSyntaxError) as e:
                logging.getLogger(self._name).warn('Error when parsing view %s' % view_id)
                print e
            self._write_button_objects(cr, 1, buttons)
        return buttons
    
    def write(self, cr, uid, ids, vals, context=None):
        """
        Update button access rules for this view
        """
        if not isinstance(ids, list):
            ids = [ids]
        
        rules_pool = self.pool.get('msf_button_access_rights.button_access_rule')
        model_pool = self.pool.get('ir.model')
        
        arch = vals.get('arch', False)

        for i in ids:
            # get old view xml
            view = self.browse(cr, 1, i)
            xml = arch or view.arch
            
            # parse the old xml into a list of button dictionaries
            try:
                buttons = self.parse_view(xml)
            except (ValueError, etree.XMLSyntaxError) as e:
                logging.getLogger(self._name).warn('Error when parsing view %s: %s' % (i, e))
                buttons = False
                
            # if we have some buttons we need to create/update Button Access Rule's from them
            if buttons:
                model_search = model_pool.search(cr, 1, [('model','=',view.model)])
                
                if model_search:
                    model_id = model_search[0]
                    rule_id_list = []
                    
                    # for each button in the old view, update it with the new view_id and model_id
                    for button in buttons:
                        button.update({'view_id': i, 'model_id': model_id})
                        
                        # look for existing BAR's with the same name and view_id
                        existing_button_search = rules_pool.search(cr, 1, [('view_id', '=', i),('name','=',button['name']),'|',('active','=',True),('active','=',False)])
                        if existing_button_search:
                            # a BAR exists so update it with the new view information and append the id to the list of existing BAR's
                            rules_pool.write(cr, 1, existing_button_search[0], {'label':button['label'], 'type':button['type'], 'model_id': model_id, 'active':True})
                            rule_id_list.append(existing_button_search[0])
                        else:
                            # does not exist so create it (First convert group xml ids to db ids)
                            if button['groups']:
                                button['group_ids'] = []
                                data_pool = self.pool.get('ir.model.data')
                                for g in button['groups'].split(','):
                                    g_split = g.strip().split('.',1)
                                    if len(g_split) == 2:
                                        try:
                                            group = data_pool.get_object(cr, 1, g_split[0], g_split[1])
                                            if group:
                                                group_id = group.id
                                                button['group_ids'].append(group_id)
                                        except ValueError:
                                            pass
                                del button['groups']
                                if button['group_ids']:
                                    button['group_ids'] = [(6, 0, button['group_ids'])]
                            # create BAR and append it's ID to the list of BAR's
                            rule_id_list.append(rules_pool.create(cr, 1, button))
                            
                    # now we have a list of buttons, of corresponding BAR's, and of all existing BAR's. Set inactive each BAR which is now un-needed
                    rules_search = rules_pool.search(cr, 1, [('view_id', '=', i)])
                    for id in rule_id_list:
                        if rules_search.count(id):
                            rules_search.remove(id)
                    rules_pool.write(cr, 1, rules_search, {'active':0})
        
        # perform the final writes to the views    
        return super(ir_ui_view, self).write(cr, uid, ids, vals, context=context) 
    
    def unlink(self, cr, uid, ids, context=None):
        # delete button access rules
        pool = self.pool.get('msf_button_access_rights.button_access_rule')
        for i in ids:
            search = pool.search(cr, uid, [('view_id','=',i)])
            pool.unlink(cr, uid, search)
            
        return super(ir_ui_view, self).unlink(cr, uid, ids, context=context)
    
    def _button_dict(self, name, label, type, groups=None, model_id=None, view_id=None):
        return {
            'name': name,
            'label': label,
            'type': type,
            'groups': groups,
            'model_id': model_id,
            'view_id': view_id,
        }
    
    def parse_view(self, view_xml_text, model_id=None, view_id=None):
        """
        Pass view_xml_text to extract button objects for each button in the view (Ignore special and position buttons). Return _button_dict pseudo object
        @raise XMLSyntaxError: thrown by lxml when there is an error while parsing the xml
        """
        
        button_object_list = []
        
        if view_xml_text:
            view_xml = etree.fromstring(isinstance(view_xml_text, unicode) and view_xml_text.encode('utf8') or view_xml_text)
            buttons = view_xml.xpath("//button[ @name and (@type != 'special' or not (@type)) and not (@position) ]")
            
            for button in buttons:
                
                name = button.attrib.get('name', '')
                label = button.attrib.get('string', '')
                groups = button.attrib.get('groups','')
                type = button.attrib.get('type', '').lower() or 'workflow'
                
                if name:
                    button_object_list.append(self._button_dict(name, label, type, groups, model_id, view_id))
                
        return button_object_list
            
    def _write_button_objects(self, cr, uid, buttons):
        data_obj = self.pool.get('ir.model.data')
        rules_pool = self.pool.get('msf_button_access_rights.button_access_rule')
        for button in buttons:
            xmlname = False
            if button.get('type') == 'action':
                model = self.pool.get('ir.actions.actions').read(cr, uid, int(button['name']), ['type'])['type']
                xmlid = data_obj.search(cr, uid, [('res_id', '=', button['name']), ('module', '!=', 'sd'), ('model', '=', model)])
                if xmlid:
                    data = data_obj.read(cr, uid, xmlid[0], ['module', 'name'])
                    xmlname = '%s.%s' % (data['module'], data['name'])
                    button['xmlname'] = xmlname
            existing_rule_search = rules_pool.search(cr, uid, [
                ('name','=',button['name']),
                ('view_id','=',button['view_id']),
                ('xmlname', '=', xmlname)
                ])
            if not existing_rule_search:
                rules_pool.create(cr, uid, button)

ir_ui_view()