建立一個Odoo Module (七)- Security、Wizard

Security

ERP中,必有一個訪問控制機制,來實現安全上的把控

Group-based access control mechanisms

Groups 就像普通的 record 一樣創建,只不過他的 model 是 res.groups。在定義menu時,可以通過設置group實現對menu的訪問權限。但是,對象仍然可以不經過menu得到訪問,所以,真正的 object 級別的訪問控制權限(read,write,create, unlink)必須在 groups 中定義好。這一過程,通常是通過在module中的 CSV 文件來設置的。但是,我們同樣可以針對 view 或者 object 中的特定 field設置控制權限,只需要對他們設置 groups 屬性。

Access rights

Access rights 是 model ir.model.access 的 record,每一條 access right 都是關聯到特定的 Model和 Group(或者不設定Group,即全局生效),還有4個permission:read,write,create,unlink。access rights通常是通過一個名爲 ir.model.access.csv 的 文件建立。

id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_idea_idea,idea.idea,model_idea_idea,base.group_user,1,1,1,0
access_idea_vote,idea.vote,model_idea_vote,base.group_user,1,1,1,0

練習 7-1
通過用戶界面,手動設置 access rights
創建一個名字爲 “John Smith”User,一個只有 read Model session 權限名爲 “OpenAcademy / Session Read”的group。

  • 通過 Settings ‣ Users ‣ Users 創建 John Smith
  • 通過 Settings ‣ Users ‣ Groups 創建 session_read,僅給予這個group read session 的權限
  • 將 John Smith 加入到 session_read 這個
  • 用 John Smith 登錄然後驗證access right 是否正確

練習 7-2
通過編輯data files,添加 access control

  • 創建openacademy/security/security.xml 用來創建 OpenAcademy Manager group
  • 編輯 openacademy/security/ir.model.access.csv 添加 access right
  • 在 openacademy/__openerp__.py中添加上面的文件

openacdemy/__openerp__.py


    # always loaded
    'data': [
        'security/security.xml', # 添加此行
        'security/ir.model.access.csv',
        'templates.xml',
        'views/openacademy.xml',
        'views/partner.xml',

openacademy/security/ir.model.access.csv

id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
course_manager,course manager,model_openacademy_course,group_manager,1,1,1,1
session_manager,session manager,model_openacademy_session,group_manager,1,1,1,1
course_read_all,course all,model_openacademy_course,,1,0,0,0
session_read_all,session all,model_openacademy_session,,1,0,0,0

openacademy/security/security.xml

<openerp>
    <data>
        <record id="group_manager" model="res.groups">
            <field name="name">OpenAcademy / Manager</field>
        </record>
    </data>
</openerp>

Record rules

a record rule 可以針對model 下的某些特定 records 設置訪問權限。同時,record rule 也是 model ir.rule 的 record,他可以關聯到特定groups,特定models,設置 read, write, create, unlink 權限,還有設置 domain, 用以設置權限應用到這個 model 下面的哪些 records
例:除了record 的狀態在 cancel 的情況下,record是不能被刪除的。

<record id="delete_cancelled_only" model="ir.rule">
    <field name="name">Only cancelled leads may be deleted</field>
    <field name="model_id" ref="crm.model_crm_lead"/>
    <field name="groups" eval="[(4, ref('base.group_sale_manager'))]"/>
    <field name="perm_read" eval="0"/>
    <field name="perm_write" eval="0"/>
    <field name="perm_create" eval="0"/>
    <field name="perm_unlink" eval="1" />
    <field name="domain_force">[('state','=','cancel')]</field>
</record>

練習 7-3
給Group “OpenAcademy / Manager”和 “Course”model 設置 record rule,只給予 responsible of a course 的寫 和刪除的權限,如果一個 course 沒有設置 responsible 的話,那麼所有人都可以對它進行 修改。
openacademy/security/security.xml

        <record id="group_manager" model="res.groups">
            <field name="name">OpenAcademy / Manager</field>
        </record>
        <!-- 新增 -->
        <record id="only_responsible_can_modify" model="ir.rule">
            <field name="name">Only Responsible can modify Course</field>
            <field name="model_id" ref="model_openacademy_course"/>
            <field name="groups" eval="[(4, ref('openacademy.group_manager'))]"/>
            <field name="perm_read" eval="0"/>
            <field name="perm_write" eval="1"/>
            <field name="perm_create" eval="0"/>
            <field name="perm_unlink" eval="1"/>
            <field name="domain_force">
                ['|', ('responsible_id','=',False),
                      ('responsible_id','=',user.id)]
            </field>
        </record>
    </data>
</openerp>

Wizards

Wizard 可以通過 dynamic form 給 user 提供 交互式的sessions,a warzard 就是一個簡單的model,繼承自TransientModel ,而不是普通的Model, class TransientModel 也是繼承自 Model, 擁有Model的所有特性,但是多出如下幾點:

  • Wizard record 不是固定的,他們將會在一定時間後,就被從database中刪除掉,所以叫做 Transient
  • Wizard models 是不需要給它設置權限的,因爲任意用戶都擁有它的所有權限
  • Wizard records 可能會用到 many2one 連接到 普通的 record,但是普通的 record 是不能通過 many2one 連接到 wizard records

我們將要創建一個wizard,使得我們可以對 一個或多個 session ,一次性選擇好他們的 attendees。


練習 7-4
創建一個wizard model,內含 一個關聯到 session的many2one field,一個關聯到 Partner 的 many2many field
openacademy/__init__.py

from . import controllers
from . import models
from . import partner
from . import wizard # new line

openacademy/wizard.py

# -*- coding: utf-8 -*-

from openerp import models, fields, api

class Wizard(models.TransientModel):
    _name = 'openacademy.wizard'

    session_id = fields.Many2one('openacademy.session',
        string="Session", required=True)
    attendee_ids = fields.Many2many('res.partner', string="Attendees")

Launching wizards

Wizards 是通過 ir.actions.act_window 被調用,在這個action中設置 field target 爲 new,這樣設置之後,通過menu點擊觸發action,將會打開一個新的窗口。
還有另一種方式開啓wizard,在 ir.actions.act_window 中添加 field src_model, 指定特定的model才能調用action,The wizard will appear in the contextual actions of the model, above the main view. Because of some internal hooks in the ORM, such an action is declared in XML with the tag act_window.

<act_window id="launch_the_wizard"
            name="Launch the Wizard"
            src_model="context.model.name"
            res_model="wizard.model.name"
            view_mode="form"
            target="new"
            key2="client_action_multi"/>

Wizard 也擁有普通 views的特性,但是 它的button可以設置 special="cancel",用以關閉窗口,且wizard中執行的其它操作,將不會生效。


練習 7-5

  • 給 wizard 定義一個 form view
  • 添加一個 action 用以調用 wizard,同時將action 的 src_model 設置爲 Session model
  • 在 wizard 中給 session field 一個默認值,這個可以通過 self._context 拿到當前的

openacademy/wizard.py

class Wizard(models.TransientModel):
    _name = 'openacademy.wizard'

    def _default_session(self):
        return self.env['openacademy.session'].browse(self._context.get('active_id'))

    session_id = fields.Many2one('openacademy.session', string='Session',
        required=True, default=_default_session)
    attendee_ids = fields.Many2many('res.partner', string='Attendees')

openacademy/views/openacademy.xml

                  parent="openacademy_menu"
                  action="session_list_action"/>
        <!-- 新增 -->
        <record model='ir.ui.view' id='wizard_form_view'>
            <field name='name'>wizard.form</field>
            <field name='model'>openacademy.wizard</field>
            <field name='arch' type='xml'>
                <form string='Add Attendees'>
                    <group>
                        <field name='session_id'/>
                        <field name='attendee_ids'/>
                    </group>
                </form>
            </field>
        </record>

        <act_window id='launch_session_wizard'
                    name='Add Attendees'
                    src_model='openacademy.session'
                    res_model='openacademy.wizard'
                    view_mode='form'
                    target='new'
                    key2='client_action_multi'/>
        <!-- 結束 -->
    </data>
</openerp>

練習 7-6
在wizard 添加一個button, 實現將 session 和 partern 關聯起來的功能
openacademy/views/openacademy.xml

                        <field name="attendee_ids"/>
                    </group>
                    <!-- 新增 footer -->
                    <footer>
                        <button name="subscribe" type="object"
                                string="Subscribe" class="oe_highlight"/>
                        or
                        <button special="cancel" string="Cancel"/>
                    </footer>
                </form>
            </field>
        </record>

openacademy/wizard.py

    session_id = fields.Many2one('openacademy.session',
        string="Session", required=True, default=_default_session)
    attendee_ids = fields.Many2many('res.partner', string="Attendees")

    # 新增
    @api.multi
    def subscribe(self):
        self.session_id.attendee_ids |= self.attendee_ids
        return {}

練習 7-7
將 attendee_ids 一次賦給 多個session
openacademy/views/openacademy.xml

                <form string="Add Attendees">
                    <group>
                        <field name="session_ids"/> <!-- 修改 -->
                        <field name="attendee_ids"/> 
                    </group>
                    <footer>
                        <button name="subscribe" type="object"

openacademy/wizard.py

class Wizard(models.TransientModel):
    _name = 'openacademy.wizard'

    def _default_sessions(self):
        return self.env['openacademy.session'].browse(self._context.get('active_ids')) # ids
    # ids
    session_ids = fields.Many2many('openacademy.session', 
        string="Sessions", required=True, default=_default_sessions)
    attendee_ids = fields.Many2many('res.partner', string="Attendees")

    @api.multi
    def subscribe(self):
        # modified
        for session in self.session_ids:
            session.attendee_ids |= self.attendee_ids
        return {}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章