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

« back to all changes in this revision

Viewing changes to msf_field_access_rights/field_access_rule.py

  • Committer: mmu-openerp
  • Date: 2013-03-13 11:05:40 UTC
  • mfrom: (1349.29.95 button-wm)
  • mto: This revision was merged to the branch mainline in revision 1524.
  • Revision ID: mmu@openerp.com-20130313110540-gk589kzzzkw5ojro
[MERGE] uf-1652 button access rights

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
# -*- encoding: utf-8 -*-
 
3
##############################################################################
 
4
#
 
5
#    OpenERP, Open Source Management Solution
 
6
#    Copyright (C) 2011 TeMPO Consulting, MSF. All Rights Reserved
 
7
#    Developer: Max Mumford
 
8
#
 
9
#    This program is free software: you can redistribute it and/or modify
 
10
#    it under the terms of the GNU Affero General Public License as
 
11
#    published by the Free Software Foundation, either version 3 of the
 
12
#    License, or (at your option) any later version.
 
13
#
 
14
#    This program is distributed in the hope that it will be useful,
 
15
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
#    GNU Affero General Public License for more details.
 
18
#
 
19
#    You should have received a copy of the GNU Affero General Public License
 
20
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
#
 
22
##############################################################################
 
23
 
 
24
from osv import osv
 
25
from osv import fields
 
26
from osv import orm
 
27
import psycopg2
 
28
 
 
29
class field_access_rule(osv.osv):
 
30
    """
 
31
    Lets user create access and sync propagation rules for fields of models.
 
32
    This class defines which model, instance level and groups to target
 
33
    """
 
34
 
 
35
    _name = "msf_field_access_rights.field_access_rule"
 
36
    _description = 'Field Access Rule'
 
37
 
 
38
    _columns = {
 
39
        'name': fields.char('Name', size=256, required=True),
 
40
        'model_id': fields.many2one('ir.model', 'Model', help='The type of data to which this rule applies', required=True, ondelete='cascade'),
 
41
        'model_name': fields.char('Model Name', size=256, help='The technical name for the model. This is used to make searching for Field Access Rules easier.'),
 
42
        'instance_level': fields.selection((('hq', 'HQ'), ('coordo', 'Coordo'), ('project', 'Project')), 'Instance Level', help='The Instance Level that this rule applies to'),
 
43
        'domain_id': fields.many2one('ir.filters', 'Filter', domain='[("model_id","=",model_name)]', ondelete="set null", help='Choose a pre-defined Filter to filter which records this rule applies to. Click the Create New Filter button, define some seach criteria, save your custom filter, then return to this form and type your new filters name here to use it for this rule. Note: Due to a technical constraint, all "like" or "ilike" operators will be automatically replaced with "=".'),
 
44
        'domain_text': fields.text('Advanced Filter', help='The Filter that chooses which records this rule applies to'),
 
45
        'group_ids': fields.many2many('res.groups', 'field_access_rule_groups_rel', 'field_access_rule_id', 'group_id', 'Groups', help='A list of groups that should be affected by this rule. If you leave this empty, this rule will apply to all groups.'),
 
46
        'field_access_rule_line_ids': fields.one2many('msf_field_access_rights.field_access_rule_line', 'field_access_rule', 'Field Access Rule Lines', help='A list of fields and their specific access and synchronization propagation rules that will be implemented by this rule. If you have left out any fields, users will have full write access, and all values will be synchronized when the record is created or editted.', required=True),
 
47
        'comment': fields.text('Comment', help='A description of what this rule does'),
 
48
        'active': fields.boolean('Active', help='If checked, this rule will be applied. This rule must be validated first.'),
 
49
        'status': fields.selection((('not_validated', 'Not Validated'), ('validated', 'Model Validated'), ('domain_validated', 'Filter Validated')), 'Status', help='The validation status of the rule. The Filter must be valid for this rule to be validated.', required=True),
 
50
    }
 
51
 
 
52
    _defaults = {
 
53
        'active': False,
 
54
        'status': 'not_validated'
 
55
    }
 
56
 
 
57
    _sql_constraints = [
 
58
        ('name_unique', 'unique (name)', "The name you have chosen has already been used, and it must be unique. Please choose a different name."),
 
59
        ('domaintext_ilike1', 'check(domain_text <> $$"like"$$)', 'Due to technical constraints, you cannot use the operator "ilike" in a domain'),
 
60
        ('domaintext_ilike2', "check(domain_text <> $$'like'$$)", 'Due to technical constraints, you cannot use the operator "ilike" in a domain'),
 
61
        ('domaintext_like1', 'check(domain_text <> $$"ilike"$$)', 'Due to technical constraints, you cannot use the operator "like" in a domain'),
 
62
        ('domaintext_like2', "check(domain_text <> $$'ilike'$$)", 'Due to technical constraints, you cannot use the operator "like" in a domain'),
 
63
    ]
 
64
    
 
65
    def create(self, cr, user, vals, context=None):
 
66
        
 
67
        # get model_name from model
 
68
        vals['model_name'] = self.pool.get('ir.model').browse(cr, user, vals['model_id'], context=context).model
 
69
        return super(field_access_rule, self).create(cr, user, vals, context=context)
 
70
 
 
71
    def write(self, cr, uid, ids, values, context=None):
 
72
 
 
73
        if not isinstance(ids, (list, tuple)):
 
74
            ids = [ids]
 
75
 
 
76
        # if domain_text has changed, change status to not_validated
 
77
        if values.get('domain_text'):
 
78
            if len(ids) == 1:
 
79
                record = self.browse(cr, uid, ids[0], context=context)
 
80
                domain_text = getattr(record, 'domain_text', '')
 
81
 
 
82
                if domain_text != values['domain_text']:
 
83
                    values['status'] = 'validated'
 
84
            else:
 
85
                values['status'] = 'validated'
 
86
 
 
87
        # deactivate if not validated
 
88
        if 'status' in values and values['status'] == 'validated':
 
89
            values['active'] = False
 
90
 
 
91
        return super(field_access_rule, self).write(cr, uid, ids, values, context=context)
 
92
    
 
93
    def copy(self, cr, uid, id, default, context=None):
 
94
        raise orm.except_orm('Duplication Disabled', 'The duplication feature has been disabled for Field Access Rules')
 
95
 
 
96
    def onchange_model_id(self, cr, uid, ids, model, context=None):
 
97
        if model:
 
98
            model = self.pool.get('ir.model').browse(cr, uid, model, context=context)
 
99
            return {'value': {'model_name': model.model}}
 
100
        else:
 
101
            return {'value': {'model_name': ''}}
 
102
 
 
103
    def onchange_domain_id(self, cr, uid, ids, domain_id):
 
104
        """
 
105
        Returns the corresponding domain for the selected pre-defined domain filter after replacing like and ilike with '='
 
106
        """
 
107
        if domain_id:
 
108
            df = self.pool.get('ir.filters').browse(cr, uid, domain_id)
 
109
            df.domain = df.domain.replace("'ilike'", "'='").replace('"ilike"', '"="').replace("'like'","'='").replace('"like"','"="')
 
110
            return {'value': {'domain_text': df.domain, 'status': 'validated', 'active': False}}
 
111
        else:
 
112
            return {'value': {'domain_text': '', 'status': 'validated', 'active': False}}
 
113
 
 
114
    def onchange_domain_text(self, cr, uid, ids, domain_text, context=None):
 
115
        if domain_text:
 
116
            return {'value': {'status': 'validated', 'active': False}}
 
117
        else:
 
118
            return True
 
119
 
 
120
    def validate_button(self, cr, uid, ids, context=None):
 
121
        return self.write(cr, uid, ids, {'status':'validated'}, context=context)
 
122
 
 
123
    def create_new_filter_button(self, cr, uid, ids, context=None):
 
124
        """
 
125
        Send the user to the list view of the selected model so they can save a new filter
 
126
        """
 
127
        assert len(ids) <= 1, "Cannot work on list of ids longer than one"
 
128
 
 
129
        record = self.browse(cr, uid, ids[0])
 
130
        
 
131
        # search in ir.ui.view for form and tree views for this model. If they exist, return action, else return None, otherwise openerp will error
 
132
        view_pool = self.pool.get('ir.ui.view')
 
133
        form = view_pool.search(cr, 1, [('type','=','form'),('model','=',record.model_name)])
 
134
        tree = view_pool.search(cr, 1, [('type','=','tree'),('model','=',record.model_name)])
 
135
        
 
136
        if form and tree:
 
137
            res = {
 
138
                'name': 'Create a New Filter For: %s' % record.model_id.name,
 
139
                'res_model': record.model_id.model,
 
140
                'type': 'ir.actions.act_window',
 
141
                'view_type': 'form',
 
142
                        'view_mode':'tree,form',
 
143
                'target': 'new', 
 
144
            }
 
145
            return res        
 
146
        else:
 
147
            raise osv.except_osv('No List View', 'The chosen model has no List view so this feature cannot be used. You can still manually type a filter in the Advanced Filter field...')
 
148
 
 
149
    def generate_rules_button(self, cr, uid, ids, context=None):
 
150
        """
 
151
        Generate and return field_access_rule_lines for each field of the model and all inherited models, with Write Access checked
 
152
        """
 
153
        
 
154
        if ids:
 
155
            fields_pool = self.pool.get('ir.model.fields')
 
156
            
 
157
            for id in ids:
 
158
                record = self.browse(cr, uid, id)
 
159
                if record.field_access_rule_line_ids:
 
160
                    raise osv.except_osv('Remove Field Access Rule Lines First From %s' % id, 'Please remove all existing Field Access Rule Lines before generating new ones')
 
161
        
 
162
                fields_search = fields_pool.search(cr, uid, [('model_id', '=', record.model_id.id)], context=context)
 
163
                fields = fields_pool.browse(cr, uid, fields_search, context=context)
 
164
        
 
165
                res = [(0, 0, {'field': i.id, 'field_name': i.name}) for i in fields]
 
166
                self.write(cr, uid, id, {'field_access_rule_line_ids': res})
 
167
        return True
 
168
 
 
169
    def manage_rule_lines_button(self, cr, uid, ids, context=None):
 
170
        """
 
171
        Send the user to a list view of field_access_rule_line's for this field_access_rule.
 
172
        """
 
173
        assert len(ids) <= 1, "Cannot work on list of ids != 1"
 
174
 
 
175
        this = self.browse(cr, uid, ids, context=context)[0]
 
176
        x, view_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'msf_field_access_rights', 'field_access_rule_full_tree_view')
 
177
 
 
178
        return {
 
179
            'type': 'ir.actions.act_window',
 
180
            'name': 'Field Access Rule Lines for rule: %s' % this.name,
 
181
            'view_type': 'form',
 
182
                        'view_mode':'tree,form',
 
183
                        'view_id': [view_id],
 
184
            'target': 'new',
 
185
            'res_model': 'msf_field_access_rights.field_access_rule_line',
 
186
            'context': {
 
187
                'search_default_field_access_rule': ids[0],
 
188
            },
 
189
        }
 
190
 
 
191
    def validate_domain_button(self, cr, uid, ids, context=None):
 
192
        """
 
193
        Validates the domain_text filter, and if successful, changes the Status field to validated
 
194
        """
 
195
        assert len(ids) <= 1, "Cannot work on list of ids != 1"
 
196
 
 
197
        exception_title = 'Invalid Filter'
 
198
        exception_body = 'The filter you have typed is invalid. You can create a filter using the Create New Filter button'
 
199
 
 
200
        record = self.browse(cr, uid, ids[0], context=context)
 
201
 
 
202
        if record.domain_text:
 
203
            pool = self.pool.get(record.model_name)
 
204
            if not pool:
 
205
                raise osv.except_osv('Invalid Model', 'The model you have chosen is invalid. Please use the auto-complete to choose a valid one.')
 
206
 
 
207
            try:
 
208
                domain = eval(record.domain_text)
 
209
                if not isinstance(domain, list):
 
210
                    raise osv.except_osv(exception_title, exception_body)
 
211
            except SyntaxError:
 
212
                raise osv.except_osv(exception_title, exception_body)
 
213
 
 
214
            try:
 
215
                pool.search(cr, uid, domain, context=context)
 
216
            except (ValueError, psycopg2.ProgrammingError):
 
217
                raise osv.except_osv(exception_title, exception_body)
 
218
 
 
219
            self.write(cr, uid, ids, {'status': 'domain_validated'}, context=context)
 
220
            return True
 
221
        else:
 
222
            self.write(cr, uid, ids, {'status': 'domain_validated'}, context=context)
 
223
            return True
 
224
 
 
225
field_access_rule()