Plone工作流的管理
One of Plone's many strengths is the workflow component. Workflow fits into one of the core themes of content management, which...
One of Plone's many strengths is the workflow component. Workflow fits into one of the core themes of content management, which is the separation of logic, content, and presentation. This chapter therefore covers Plone's workflow in detail.
Plone的强大功能之一是工作流组件。工作流是 内容管理 的核心主题之一,它将逻辑、内容、和呈现分离开来。本章将详细讲述Plone的工作流。
The chapter starts by covering some key definitions related to workflow, as well as the key tools involved, so that you can begin to conceptualize workflows. Once these concepts are clear, I then discuss how to add and edit your own workflows.
本章从工作流相关的关键定义、及涉及的关键工具开始,这样你就能够建立起工作流的概念。一旦这些概念清晰了,我就会讨论如何添加和编辑你自己的工作流。
Throughout this chapter, I reference simple changes you can make to the workflow that comes straight out of the box with Plone. I also provide a series of examples to help you perform tasks such as creating notifications, moving content, and so on. Finally, I show some of the more advanced features of workflow development and some of the useful tools that are available.
本章节中,我引用到的工作流,是Plone自带的,你可以对它进行简单的修改。我还提供一系列例子帮助你执行一些创建通知、移动内容等的任务。最后,我会展示一些关于工作流开发的更高级的特性,以及一些有用的工具。
什么是工作流?Workflow is a chain of actions or events that occurs on something to achieve an objective. Workflow often expresses business rules that may exist. Every business has different rules and policies about tasks that must happen within that company. Examples of this include the following: 工作流 是一连串的动作或事件,它们发生在某件事情上,以达到某个目的。工作流通常代表已经存在的业务规则。每项业务都有关于任务的不同规则和策略,这些任务必须在其组织中发生。这样的例子有一些:
Workflow separates the logic of these business rules and standardizes the concept of thinking about these changes. By having separate logic, it's now easy for businesses to change the application to fit their business and their business rules. Often applications try to enforce a workflow on a business because the workflow is hard-coded into the application. 工作流把这些业务规则中的逻辑分开,并规范化考虑这些变化的概念。由于具有独立的逻辑,企业就容易修改应用程序来适用他们的业务及其业务规则。通常,应用程序试图对某项业务强制使用一种工作流,因为工作流被硬编码到应用程序中。 理解Plone中的工作流Plone's workflow tool provides certain features and limitations that are key to understanding workflow in Plone. The workflow product used in Plone is DCWorkflow, which is an open-source product released by Zope Corporation. Other workflow systems are available, and some of them are being incorporated into Plone, such as OpenFlow (http://www.openflow.it). However, for the moment, DCWorkflow is powerful and simple enough to provide all the functionality most users will need. Plone的工作流工具提供了某些特性和局限性,这些特性和局限性时理解Plone中的工作流的关键。Plone中采用的工作流产品时DCWorkflow,它是Zope公司发行的开源产品。还有其他一些工作流系统,有些已经被集成到Plone中,例如 OpenFlow 。 不过,到目前为止,DCWorkflow是一个易用、足以提供绝大部分用户所需功能的强大的工作流。 DCWorkflow assumes there's one object in the system that's the target of the workflow-for example, one piece of content or one widget. It further assumes that all objects of the same type go through the same workflow. By repurposing content (see Chapter 11 for more on this), you can have similar content use different workflows. DCWorkflow假设在一个工作流的目标系统中有一个对象 - 例如:一段内容或一个窗件。它进一步假设所有相同类型的对象采用同样的工作流。通过重新定制内容类型(详见第十一章),你可以让相似的内容采用不同的工作流。 Since the DCWorkflow system is included in Plone, there's nothing extra to install. It's represented in the Zope Management Interface (ZMI) by the portal_workflow object. 由于Plone中已经包含了DCWorkflow系统,不需要另外安装其他软件。DCWorkflow在Plone实例的ZMI中用 portal_workflow 对象表示。 建立工作流的概念Before explaining a workflow, I'll explain a few simple pieces of terminology: states and transitions. 在解释工作流之前,我要解释一些简单的术语:状态和转换。 A state is information about an item of content at a particular moment in time. Examples of states are private, public, pending, and draft. All workflows have at least one starting state in which all the content starts. The workflow will then move the content through a series of states, either by user interaction or by some automation process. When the content reaches an end state, it'll remain in that state for a long time (usually forever). Content may reach one or more different end states in the process of a workflow. 一个 状态 是某个特定时刻下、关于内容对象的信息。状态的例子有 私有 、*公开* 、*待审核* 、和 草稿 。所有的工作流至少有一个开始状态,它是所有内容的初始状态。工作流会通过用户交互的方式、或者通过某些自动过程的方式,把内容在一系列状态间移动。当内 容到达某个结束状态时,它会保持在该状态一段很长的时间(通常是永远保存这个状态)。在一个工作流的处理过程中,内容可以到达一个或者多个不同的结束状 态。 For that piece of content to move from one state to another, a transition is needed. A transition connects a starting state and an ending state. A transition can have lots of different features associated with it, as you'll see later, but for the moment, you just need to know that a transition moves content between two states. Usually a transition is triggered by some external force, such as a user clicking a button on a Web page or a script interacting with a page. 对于要从一个状态移动到另一个状态的内容,需要一次 转换 。一个转换间一个起始状态和结束状态连接起来。一次转换可以具有相关联的许多不同特性,这一点在后面会看到,不过此时,你只需要知道一次转换让内容在两个状态间转换。通常转换有某些外力触发,比如用户点击网页中的某个按钮,或者通过某个页面交互的一个脚本。 Visualizing a workflow, especially when talking about something as nebulous as content, can be a little confusing. Thinking about an everyday occurrence will help. In this case, the following example shows the workflow of my credit card bill, which I have the joy of getting every month: 观察某个工作流,有时会有一些困惑,特别是在讨论某些像内容这样笼统的东西的时候。设想每天都会发生的事情会有帮助的。在这种情况下,下面的例子展示了我的信用卡记帐的工作流,它让我每个月都很高兴: 1.The credit card company prepares a bill and mails it to me. 2.I get the bill and put it on my desk. Sometimes the bill sits on my desk for quite a while as I wait for the end of month. Occasionally I have to query people about certain expenditures, such as "What were those clothes you bought?" 3.Any serious queries or questions then go back to the credit card company, perhaps causing a new bill to be created (although this happens quite rarely). 4.Usually at the end of the month, when I do all the accounting, I then pay the bill. 1.信用卡公司准备好帐单,并邮寄给我。 2.我收到帐单,并把它放在桌面上。有时我要等到月底再处理,所以帐单会在我的桌面上放相当长时间。偶尔我得问问某几项花费,比如"你买的哪些是什么衣服?" 3.如果有严重的问题,就要返回信用卡公司,也许会导致重建一份帐单。(尽管这种事情很少发生)。 4.通常到月底,在我做完所有的帐目后,我会支付该帐单。 From this, then, you can come up with some states. Looking at the previous steps, you'll see you really have no need to create different states for receiving the bill, which includes opening it and putting it on my desk. Similarly, you don't need to bother with every review that happens. Although these are all valid steps that take place, trying to make a workflow for every state would be too cumbersome. Instead, you can summarize the workflow with the following states: 从这里开始,你遇到了一些状态。看看前面的步骤,你会发现你其实没有必要为收到帐单创建不同的状态,尽管它包括有打开信件、把它放到我的桌面上。同样,你 不需要为每次进行是帐单审核而设置专门的状态。尽管这些都是确实会发生的步骤。建立一个包括所有状态的工作流会导致工作流过于笨重。相反,你可以用下面的 状态总结这个工作流:
Now that you've come up with the states, you can think of the changes that need to occur. For each of these states, you'll have at least one transition that occurs to move the bill from one state to another: 总结好了状态,你就可以考虑需要发生的变化。对每个状态,你至少需要发生一次转换把帐单从某个状态转入另一个状态:
Figure 8-1 shows this set of transitions and states. In the figure, boxes represent states, with the state written in them. Arrows represent the transitions from one state to the next, with the name of the transition in italics.
Figure 8-1. A simple state machine for paying credit card bills 图8-1. 信用卡帐单支付的简单状态机。 You've now extracted this business process of paying a credit card bill into a workflow. The next step is to think about roles and security for this credit card bill. This workflow now contains the business logic for an application for processing credit cards. 你现在已经把信用卡帐单支付的业务过程中提取到一个工作流中了。下一步,要考虑这信用卡帐单的角色和权限了。这个工作流现在包含一个处理信用卡的应用的业务逻辑。 理解工作流中的角色和安全控制In any complicated system, you'll have users of all roles and groups. These roles give Plone a large amount of flexibility with security, but they also can make it more complicated. Chapter 9 covers security, local roles, and groups, but this section covers some key points about how these topics relate to workflow. 在复杂系统中,都会有各种角色的用户和用户组。这些角色使得Plone具有安全控制上的大量灵活性,也使它变得更加复杂。第九章讲述了安全、本地角色、和用户组,本节讲述与工作流相关的这方面的关键要点。 When a piece of content moves from one workflow state to another, the workflow process can change the security settings on that content. The security settings determine what user can perform what action on what piece of content. By manipulating the security settings through workflow, you can cause the security to change on a piece of content through its life cycle. Users from static systems or Zope often get confused because in Zope, all pieces of content have the same security settings throughout their life cycle. 当某项内容从工作流的一个状态转到另一个状态时,工作流处理程序可以修改这项内容的安全设置。安全设置决定了什么用户可以对什么内容执行什么动作。通过使 用工作流来设置安全权限,你可以让一个内容的安全设置在他的生命周期中发生变化。静态系统或Zope的用户常常会感觉到困惑,因为在Zope中,所有的内 容在他们的整个生命周期中的安全设置都是一样的。 Returning to the credit card example, you can infer the security settings for the credit card bill. One way to represent this is to produce a table that expands the security in general terms for the transitions that can occur at each of the various states, as shown in Table 8-1. 回到信用卡帐单的例子,你可以推断出信用卡帐单的安全设置。表示安全设置的一种方法是做一张表,每个状态可能发生的转换的安全设置都列出来,如表8-1所示。 Table 8-1. The Transitions and Entities That Can Make Them 表8-1。 转换与可以执行转换的元素
At this stage in Table 8-1, you've seen the transitions and who can make them. You haven't thought about the access that each user has to perform an action on an object at each point. For example, at which point can someone edit the bill, and when can it be viewed? These are called actions in Plone terminology, as shown in Table 8-2. I hope that only I have access to my own credit card statements! Likewise, at any stage, the bank is able to view the credit card bill and answer queries on it. 从表8-1中,你可以看到各种转换以及谁能够执行转换。你还没有考虑过:每个用户在每个点上要对某个对象执行某个动作。例如,在哪个点上,某个人可以编辑帐单,以及何时该帐单可以被查看?在Plone的术语中,这些被称为 动作 , 如表8-2所示。 我希望自由我能够访问我自己的信用卡状态!同样,任何时候,银行都能够查看该帐单,并在它上面回复问题。 Table 8-2. The Actions and Entities That Can Make Them 表8-2. 各种动作以及可执行他们的元素。 表 8-2。
Actually, as it turns out, I can't edit my credit card bill; only the bank can. I can send back my credit bill by rejecting it, but the bank is unlikely to want my edits. In this situation, assume the bank is the owner of the credit card bill. This demonstrates a concept called ownership. I may have several credit card bills from several banks, and in each case you can think of the bank as the owner. Each bank owns its own credit card bills, but Bank A isn't the owner of Bank B's bill. Table 8-3 combines the transitions and actions, changing the terms Me and Bank to Payee and Owner, respectively. 实际上,我不能够编辑信用卡帐单;只有银行才可以编辑帐单。我可以通过拒付来退回帐单,当银行不愿意要我的编辑。在这种情况下,假设银行是信用卡帐单的所有者。这里演示了一个叫做 ownership 所有者的概念。我有来自几家银行的数张信用卡帐单,每种情况下我都可以把银行看做是帐单的所有者。每个银行拥有自己的信用卡帐单,但是银行A不是银行B的帐单的所有者。表8-3把转换、动作组合起来,并相应地把 我 和 银行 换成 支付人 和 所有者 。 Table 8-3. The Transitions and Actions Combined, plus the Roles of People 表8-3. 转换、动作的组合,加上人员角色
Of course, this is a rather contrived example, but it illustrates how you can apply workflow to basic states. More transitions can occur here-for instance, I'd be more than happy for someone else to pay my credit card bill for me-but that's so unlikely that you shouldn't add it to the workflow or security. 当然这是一个人为的例子,但它演示了你如何把工作流应用到基本的状态中。在这里,可以发生更多中的转换- 比如,如果有人帮我支付信用卡帐单,我会非常高兴 - 但是那是非常不可能的,因此你不应当把它加到工作流或安全设置中去。 Before showing how to create and edit workflows, I'll now show you the default workflows that ship with Plone. 在讲述如何创建和编辑工作流之前,我要介绍一下Plone自带的工作流。 Plone中的工作流介绍Plone ships with a set of default workflows for your Plone site. These workflows provide a logical way of moving content through a Plone site. A standard Plone site ships with two workflows: the default workflow and the folder workflow. The following sections present each of these in turn. Plone自带了为Plone站点设计的一系列工作流。这些工作流提供了在Plone站点中移动内容的逻辑方法。标准的Plone站点有两种工作流:缺省工作流和文件夹工作流。下面,我们将依次简介这两种工作流。 缺省工作流Chapter 3 covered the default workflow and the default settings when publishing content. I discussed the security and settings for each state in the workflow. However, a picture is worth a thousand words, so Figure 8-2 shows the workflow state.
Figure 8-2. The default workflow for content that comes with Plone 图8-2. Plone自带的缺省的内容发布工作流 Figure 8-2 shows the main states and the transitions. This figure has a gray dotted line that represents a sort of security divider. To the left of the line is where owners of the content usually interact with the content. To the right of the line is where reviewers usually interact with the content. 图8-2 显示了主要的状态和转换。图中虚线把不同的安全设置区分开来。在虚线左边是内容所有者与内容的交互。虚线右边是审核者与内容的交互。 NOTE The owner of the content is the person who created the content originally. An owner is one particular member of a Plone site. Although many members exist in a Plone site, only one person can be the owner of a piece of content in a Plone site. Because the owner role is calculated when an object is created, the owner role is special. 注意 内容的所有者是内容的最初创建者。一个所有者,是Plone站点中某个特定的成员。尽管在一个Plone站点中有许多成员,只有一个人员可以是某段内容的所有者。由于所有者角色是在对象被创建时被计算出来的,因此,所有者角色是很特殊的。 Just like with the credit card example, an associated set of permissions exists for the default workflow. Table 8-4 outlines all the permissions and the states. 就像那个信用卡帐单的例子一样,缺省工作流也有相关的一系列权限设置。表8-4列出了所有的权限和状态。 Table 8-4. The Default Workflow Permissions 表8-4. 缺省工作流的权限设置
As you can see from Table 8-4, by default only when content is in the private state is it truly hidden from everyone else. When content is in the published state, only the manager can edit it. Later in the "Editing Permissions" section, I'll show you how to change these permissions easily through the Web. 在表8-4中你可以看到,缺省情况下,当内容处于私有状态是,对其他人都是隐藏的。当内容处于被发布的状态时,只有管理员可以编辑。在后面的"编辑权限"一节中,我会讲解如何通过Web轻松地修改这些权限。 文件夹工作流I also discussed the folder workflow in Chapter 3, when I covered publishing content with you. However, as I noted in that chapter, no pending state exists for folders. Instead, you have a slightly simpler workflow, as shown in Figure 8-3.
Figure 8-3. The folder workflow for content that comes with Plone 图8-3。 Plone自带的文件夹工作流 其他工作流Numerous workflows are available to a Plone site, including private workflow, community workflow, one-step publication workflow, and so on. ZopeZen comes with a workflow, and PloneCollectorNG also comes with a workflow. DCWorkflow comes with four workflows. 对于Plone站点而言,有许多种工作流可用,包括私有工作流、社区工作流、单步发布工作流等等。ZopeZen就带有一种工作流,PloneCollectorNG也带有自己的工作流。DCWorkflow带有4种工作流。 Currently, two workflows come in the PloneWorkflows product in the collective project on SourceForge (http://sf.net/projects/collective): the community workflow and one-step publication workflow. The community workflow is similar to the Plone workflow, with a few changes. The one-step publication workflow has two states: private and published. 目前,PloneWorkflow产品有两种工作流。社区工作流和单拍发布工作流。社区工作流与Plone工作流类似,只有一些修改。单拍发布工作流只有两种状态:私有和发布。 At the moment, you have no easy way to install and uninstall workflows, and you have no real easy way to transition content between one state and another. For example, if you install the one-step publication workflow into an existing state, you also need to fix the states for all objects and move them into one of the new states. In this case, it's probably simple-everything in a published state should stay as it is, and everything else should move into the private state. 此时,没有什么好办法安装和卸载工作流,也没有什么真正简单的方法把内容从一种状态转换到另一种状态。例如在某个原有站点上安装单拍发布工作流,你还需要 把所有对象的状态进行修复,然后把他们转入新工作流具有的新状态之一。在这种情况,非常简单-所有已发布的对象可以不变,把其他所有对象都转为私有状态。 添加和编辑工作流Now that I've discussed the default workflow, I come to the key point that's probably most on your mind: How can you change the defaults? Well, as with most of Plone, you can add, edit, and delete all workflow through the ZMI. The tool that controls workflow is portal_workflow. In the following sections, I cover how workflows are assigned and then go through all the settings for a workflow in detail. 我们已经讨论了缺省工作流,我现在来说说萦绕在你脑海中的几个关键点:我怎样修改缺省的工作流?好,像Plone的大部分功能一样,你可以通过ZMI对所有的工作流进行添加、编辑和删除。控制工作流的工具是 portal_workflow 。以下章节中,我会讲述工作流是如何被分配的,然后详细讲解工作流的所有设置。 为一个内容类型设置工作流After clicking portal_workflow, you'll see a list of workflow assignments. A feature of DCWorkflow is that each content type has one and only one workflow assigned to it; Figure 8-4 shows these assignments.
Figure 8-4. The list of workflow by type 图8-4 工作流按类型列表 On this page you'll see a list of each content type and the workflow that has been applied to it. If a workflow isn't specified (in other words, the value is blank), then no workflow is applied. As an example, the default for the Portal Site type is blank. You really don't want to try transitioning the Plone site itself, just the objects in it. If the value is (Default), the default workflow at the bottom of the page is applied to that content type. In Figure 8-4, for topic and folders, the folder_workflow workflow is used, and for all other content types, plone_workflow is applied. The names of the workflow refer to the name of workflow objects imported or created inside the workflow tool. For more information on the workflows available, select the Contents tab. This opens a list of workflows that have been loaded into the system, as shown in Figure 8-5.
Figure 8-5. Workflows available 图8-5. 可用工作流。 You can add workflows by clicking the Add Workflow button. This opens a list of the workflows available; to create a workflow, select a workflow type and enter a workflow name. To create workflow that's empty but that's configurable through the Web, select dc_workflow and enter an appropriate name; for example, enter my_workflow. 你可以点击 Add Workflow 按钮来添加工作流。点击后会打开可用工作流的列表;要常见工作流,选择工作流类型,然后输入工作流的名称。要创建空的、可通过Web来配置的工作流,选择 dc_workflow , 然后输入适当的名字; 例如,输入 my_workflwo 。 编辑一个工作流From the Contents tab, you can click a workflow to access the management screens for that workflow: all the states, transitions, and associated features. The series of tabs across the top of the page outlines the functionality of a workflow quite well: States, Transitions, Variables, Worklists, Scripts, and Permissions. I'll run through each of these tabs and some of the other options available. Unless otherwise mentioned, all the following tabs are accessible from this main workflow page. 在Cotents页签中,点击某个工作流可进入该工作流的管理界面:所有的状态、转换、和相关特性。页面顶部的页签很好地列出了工作流的功能:状态、转 换、变量、工作列表、脚本、和权限。我会逐一介绍每个页签及其他相关选项。除非特别提到,以下所有的页签都是从工作流管理主界面的页签进入的。 Creating or editing workflow can require lots of clicking and can be a little confusing. If you're a developer keen on using the file system, then you can do all this from Python if you want-I cover this for you later in this chapter in the "Writing a Workflow in Python" section. 创建和编辑工作流需要很多次的点击,常常会造成一些迷惑。如果你是开发人员,最好使用文件系统,你可以用Python来实现所有的功能。- 本章后面有一个 "用Python编写工作流" 的章节。 设置初始状态To set the initial state, go to the States tab and check out the states available; next to one of the states you'll see an asterisk, as shown in Figure 8-6.
Figure 8-6. Setting the initial state for this workflow 图 8-6 . 设置工作流的初始状态。 You set the initial state for your workflow on this page by checking the box next to the state and then clicking Set Initial State. All content that uses this workflow will be created with an initial state. Any content that has already been created will remain in its initial state; changing the state afterward won't change that state. You can set only one initial state for each workflow. 选定状态,点击 'Set Inital State' ,就可以为你的工作流设置初始状态。所有使用这个工作流的内容在创建时都会带有一个初始状态;以后对状态的修改不会改变这个状态。每种工作流只有一个初始状态。 如何设置初始状态为私有?On some sites it may make sense for content to not show up at all or be accessible to users other than administrators and owners only after it has been completed. The best way to do this is to set the default state for the object to something that provides this security-for example, private. In the private state, only reviewers, managers, and owners can actually see the item. 有些网站希望内容在完成后,不要显示出来,或者只让管理员和所有者访问。实现这样需求的最好的办法是把该对象的缺省状态设置成能够提供这种安全控制的某个东西 - 比如 私有。 在私有状态,只有审核员、管理员和所有者能够看到该对象。 To set the default state to private in the ZMI, click portal_workflow, and select the Contents tab. Next, click plone_workflow, select the States tab, and then select the default state by checking the box next to visible. Finally, click the Save Changes button. New content will now be in the private state and not accessible to the general public. 在ZMI中,要把缺省状态设为私有,点击 portal_workflow , 然后选择 Contents 页签。接下来,点击 plone_workflow , 选择 States页签,然后选择缺省状态为 visible 下面的选项。最后点击 Save Changes 按钮。现在,新的内容都会为私有状态,不会被公众访问到。 编辑状态The States tab lists the states that are present in this workflow. At the beginning of this chapter, I explained that a state represents an object at a particular point in time. Each state has an ID that's unique; this is usually a simple verb such as pending or published. To add a state, enter an ID and click Add at the bottom of the page. 状态页签列出了工作流中呈现的各种状态。在本章开始时,我已经解释了一个状态表示在某个特定时刻的某个对象。每个状态都有唯一的ID;通常是简单的动词,比如 pending , 或 published 。要添加状态,则输入ID,点击添加按钮。 You'll also see the following options: 你会看到以下选项: Title: The title of the state is displayed in your Plone site and is a user-friendly version of the state. Description: The description of the state is a long description of the state. This isn't currently shown to users but may be in the future. Possible transitions: This lists all the possible transitions that can occur from the state. This list will show only if you actually have a transition in the system. Simply select the transitions that need to occur on this state. By selecting a transition for this state, you're selecting the start point for this transition to be this state. To alter a state, enter the changes and then click Save to commit the changes. The Permissions tab will open with the permissions that will be applied to an object while it's in this state. This may mean changing the permissions on an object when it transitions into that state. The form is rather self-explanatory; to enable an anonymous user to view the object, check the boxes that correspond to View and Anonymous and click Save, as shown in Figure 8-7.
Figure 8-7. State permissions page 图8-7. 状态的权限页面 If you change the permissions for a particular workflow state, you've created an issue that needs resolving. Any existing content in that state won't have the new workflow permissions set on it. The content will have the old workflow permissions, and you'll need to update them. When you've finished making all your changes, go to the root workflow page and click Update Security Settings, as shown in Figure 8-4. Performing that update may take a while depending upon the number of objects to be altered. 如果你为某个特定的工作流状态修改了权限,你同时新建立一个需要解决的问题。任何已经在此状态的内容不会有新的工作流权限设置。该内容还保留原先工作流的 权限设置,你需要更改他们。全部改完后,进入工作流的首页,点击Update Security Settings, 如图8-4所示。根据要转换的对象的数量,这个更新操作可能需要一定时间。 The Variables tab allows you to assign a value to a variable when the object is in this state. The workflow determines the list of variables available to each state. For more information on these, see the "Editing Variables" section. Variables页签在该对象到达此状态时,为其中的某个变量设置某个值。工作流决定每个状态可用的变量数目。"编辑变量"一节有更多这方面的信息。 编辑转换The Transitions tab lists the transitions that will occur in this workflow. In the beginning of this chapter, I showed you how a transition represents the changes that will occur to the object. Each transition has a few variables that are shown on the summary page. To add a transition, enter an ID and click Add at the bottom of the page, as shown in Figure 8-8.
Figure 8-8. Transition details page 图8-8. 转换详细内容页面 If you now click a transition, you'll open the following details for that transition: 此时点击某个转换,会打开该转换的详细信息页面: Title: This is the title for this transition. Description: This is the detailed description for this transition. Destination state: This is the state that will be the target for this transition. The initial source state is defined by assigning the transition to the state. Trigger type: This indicates how the transition will be triggered. Automatic means that this will happen as soon as it moves into this state. Initiated by user action is the most common choice and means a user has enacted the transition by clicking a link. Script (before): This runs this script before this transition occurs. Script (after): This runs this script after this transition occurs. Guard: This is the security for this state (explained shortly). Display in actions box: This is how this transition will be displayed in Plone. Entering a value here also ensures that the transition will be entered as an action. You can then get this transition as an action by querying for actions. Of these values, the destination state is quite interesting. Although I've already mentioned that transitions normally change state, this isn't required. Because each transition can run scripts and write something into the history, it can be useful sometimes not to change state. For an example of this, see the "Using Workflow to Track Changes" section later in this chapter. If your transition does change the state, then select the new state as the destination state. 在这些值中,目标状态非常有趣。尽管我已经说过转换通常修改状态,但这并不是必须的。由于每个转换都可以运行脚本,以及向历史记录中写入某些东西,有时 不 改变状态会非常有用。 这方面的例子可参看本章的 "用工作流跟踪修改” 一节。如果你的转换确实修改状态,则选择新状态作为目标状态。 A transition can have multiple starting points but only one destination; if you need multiple destinations, you'll have to make multiple transitions. You can specify scripts to run before or after this transition. Two common examples are moving an object in workflow and sending an e-mail notification. The "Common Tasks and Examples" section covers both of these examples. 转换可以有多个起点,但只有一个终点;如果你需要多个终点,你就得建多个转换。你可以指定在此转换之前、之后执行的脚本。常见的例子有:在工作流中移动某个对象、发送email通知邮件。"常见应用和例子"一节有这些例子的讲解。 Before any transition can be executed, a security guard checks the entire transition to ensure that the user running the transition has the right to do so. The guard has the following three components: 在任何转换执行前,会进行安全防护检查整个转换,确保运行该转换的用户具有执行的权限。该防护有以下三个组件: Permission(s): These are the required permissions. Multiple permissions should have a semicolon (;) to separate them. Role(s): These are the required roles. Multiple roles should have a semicolon (;) to separate them. Expression: This is a workflow expression. For more information on this, see the "Editing Workflow Expressions" section later in this chapter. For each value specified, the guard must evaluate as true before continuing. If a test of any of the values fail, then the transition won't execute. Usually you'll find most guards have only one or two values specified. 编辑变量The Variables tab lists the variables that will be created and changed in the workflow. I haven't discussed variables much with you up to this point; instead, I've focused on states and transitions. This section covers variables. 变量页签列出了工作流中将被创建和修改的各种保留。前面都没有过多地讨论变量,而是集中讨论了状态和转换上。本章将讲解变量。 It isn't always possible, and I don't recommend that you try, to encapsulate all the information you'll need in a workflow within just states and transitions. Instead, you can use variables to store some workflow-related information. For example, in the credit card bill example, the bill could be paid by several methods (Internet banking, check, and so on). You could store the amount method ($100, for example) in a variable. Should the bill be rejected or altered, that amount would be updated. The point of a variable is to have something that changes between each state and transition. 不太可能、也不推荐把某个工作流中所需要的所有信息都仅仅封装在状态和转换中。可以使用保留来存储某些工作流相关的信息。例如,在信用卡帐单的例子中,帐 单支付可以采用集中方式(网上银行、支票等等)。你可以把金额存放在一个变量中(例如 ¥100元)。一旦帐单被拒付或调整,金额应当被更新。变量的应用要点是:保存每个状态和转换间改变的某个东西。 So, returning to the main workflow page, click the Variables tab to get a list of all the variables. To add a variable, enter a variable* ID and click Add at the bottom of the page. To determine what state an object is in at any time, DCWorkflow stores the current state in a variable on the object. The default name of that variable is *review_state. 回到工作流主页面,点击变量页签列出各种变量。要加变量,输入有效的ID,然后点击Add按钮。为了确定在任何时候确定某个对象所处的状态,DCWorkflow将当前状态保存在该对象的一个变量中。该变量的缺省名字是 review_state 。 NOTE If you need to change this because it conflicts with another name, you can do so at the bottom of that page. However, doing this will cause all your current objects to lose their state, so be careful about changing that value. 注意 如果与其他名字冲突,你要修改该变量名字,可在此页面的底部完成。不过,这样做会导致当前所有的对象丢失他们的状态,因此改这个值要非常小心。 Each workflow variable has the following properties: 每个工作流变量都有以下属性:
编辑工作列表The Worklists tab provides access to all the worklists that are assigned in this workflow. A worklist is a method of querying the workflow for information about the numbers of objects in that workflow. For example, I'd like to be able to easily ask the workflow for all the outstanding credit card bills I have. 工作列表提供对工作流中所有已指派的各种列表。 一个 worklist 是查询该工作流中有多少对象的一个方法。例如,我可以向工作流要我已有的所有信用卡帐单。 To add a worklist, enter an ID and click Add. Each worklist has the following properties: 要加一个worklist, 输入ID,点击Add。每个workllist有以下属性:
Returning to the credit card example, if I wanted to know all the credit card bills that need reviewing by me, then I could place this information in a worklist. First, the variable review_state would contain the current state for each item. All the credit card bills that need reviewing would be in the review state. Second, I'd add a worklist called review_queue, and the value for variable would be pending. I could now ask the worklist for all the items in the review_queue. 回到信用卡帐单的例子,如果我想知道所有要审核的信用卡帐单,我就可以在worklist中放入这样的信息。首先 review_state 变量会包含每个对象的当前状态。所有需要审核的信用卡帐单都会在 review 状态。第二,我可以添加一个 review_queue 的工作列表,变量的值是 pending 。我现在就可以向工作流要处于 review_queue 中的所有对象了。 Although a worklist is a convenient way of storing this information, Plone doesn't use them. Instead, Plone uses ZCatalog directly to query objects that are workflowed. Since the DCWorkflow worklist uses the catalog tool, the end result is the same. 尽管工作列表是保存该信息的便捷方式,Plone并没有用到他们。Plone使用ZCatalog直接查询被工作流控制的对象。由于DCWorkflow的工作列表也使用该类目工具,其结果是一样的。 编辑脚本The Scripts tab lists the scripts that are available this workflow. This list is actually a standard folder in the ZMI, and you can add almost anything there. Since the main reason you'd want to do this would be to add a script to perform advanced handling of transitions, you should add only Script (Python) objects here. 脚本页签列出该工作流可用的各种脚本。该列表是ZMI中的标准文件夹,你可以在这里加入任何东西。由于你要做的是加入一个脚本进行高级的转换处理,所有在此文件夹中应当只加入Python脚本对象。 To add a script from the Scripts tab, select Script (Python) from the Add drop-down menu, and give the script an ID. The script is passed one and only one object, which is the base workflow expression object; for more information on this object, see the "Editing Workflow Scripts" section later in this chapter. For example, if you need to access the actual object in the workflow, you can use a Python script such as the following: 要加脚本,从下拉菜单中选择Script(Python),给定脚本ID编号。脚本被传递给且只传递给一个对象,该对象就是工作流的表达式对象;本章后面的”编辑工作流脚本“讲述了表达式对象。例如,要访问工作流的某个对象,可以使用这样的Python脚本: System Message: WARNING/2 (<string>, line 521) Block quote ends without a blank line; unexpected unindent.##parameters=state_change obj = state_change.object What happens in this script is up to the developer-you can run almost anything here. You can trigger events, and you can access other workflows and transitions. For some example scripts, see the "Sending E-Mail Notifications" and "Moving Objects" sections later in this chapter. When the script executes, it will execute as the user who initiated the transition. You could assign proxy roles on the script if it needs to happen as someone else. Returning to the transitions, you can assign this script to any number of transitions in the script (after) and script (before) settings. You can run the script either before or after a transition. 脚本中所做的事主要由开发人员而言的-在此可以运行几乎任何东西。可以注册事件、访问其他工作流和转换。更多脚本的例子,请常见本章后面的在”发送 email通知邮件“ 和 ”移动对象“ 部分。执行脚本时,它会以启动该转换的用户的身份进行执行。如果需要作为其他角色执行,可以为该脚本指派代理角色。可以把该脚本指派给任意多的转换,方法 是使用 script(after) 和 script(before) 来设置。你可以在转换之前或之后运行此脚本。 编辑权限The Permissions tab lists the permissions that are managed by this workflow. You've seen these permissions already when examining the states. You set the list of permissions manageable in those states in this tab. To add a new permission, select the permission from the drop-down box and select Add. 权限页签列出该工作流可管理的权限。在检查状态时,已经看过这些权限的设置了。在此标签中,设置各状态中可管理的各种权限。要加新的权限,从下拉框中选择权限,选择安装。 如何编辑已发布的文档?Well, you can't edit a published document in the default workflow unless you have the manager role. If you allow the owner of the document to edit it, then you really should review it again. However, this seems to be a common request and is a trivial thing to change. In the ZMI, click portal_workflow, and select the Contents tab. Then click plone_workflow, and select the States tab. Finally, click published and then select the Permissions tab. Check the box that corresponds to allowing the owner to modify portal content.
Click Save Changes to save your permissions. Because you've updated the security settings, you'll have to click portal_workflow, select the Contents tab, and click Update security settings. This will update all the objects in your site and ensure that your permissions have been applied to existing objects. Now owners can edit their documents while they're in the published state. 点击Save,保存权限设置。权限设置已更新,你得点击 portal_workflow, 选择Contents页签,点击 Update security settings 。这样会对你网站中的所有对象进行更新,确保你的权限设置应用到已有的对象中。现在,所有者就能够在已发布状态下编辑他们的文档了。 编辑工作流脚本Scripts are an opportunity for the developer to perform some logic upon a transition. That logic can be almost anything you want. You could be checking that some conditions have been performed (for example, is the document spell checked?) or that some special actions have been performed. When the object is transitioned, the script will be called. 脚本对于开发人员来说,是在某个转换上执行某些逻辑的时机。该逻辑可以是任何你想要做的东西。你可以检查某些条件已经执行(例如,文档适合经过拼写检查?),或者某些特殊动作已经被执行。但一个对象被转换时,该脚本将被调用。 When a script is called, one extra parameter is passed to that script. That extra parameter provides access to all sorts of transition-related elements and attributes. That parameter is called the state_change parameter, and it has the following attributes:
For example, to find out what state is being transitioned to and when, the following is a Script (Python) object that will tell you just that information. This script logs the information about the transition into the log file: 例如,要找出正在被转换的会变成什么状态,何时变成该状态,下面的脚本可以完成这样的工作。该脚本把关于转换的信息记入到日志文件中: ##parameters=state_change st = 'From %s to %s on %s' % ( state_change.old_state, TIP When you're writing a Script (Python) object, you may need to print to the log file to help with debugging. A script called plone_log does this, which takes a string and passes it to Plone's logging functions. Hence, calling context.plone_log is a useful tool for debugging. 技巧 编写脚本对象时,把信息输出到日志文件对于调试会有帮助。 plone_log 脚本会做这样的日志工作,它需要一个字符串作为参数,然后把该字符串传递给Plone的日志函数。 调用 contenxt.plone_log 是调试时非常有用的工具。 When assigning a script to a transition, you have two choices: before and after. As the names suggest, a script that's set assigned to before runs prior to the transition running. This is suitable for scripts that may check if something should happen prior to the transition running, such as testing that another dependent object or page has been uploaded or there are no spelling errors. The script assigned to after runs once the transition completes-although if at any time an uncaught exception is raised on a script, this will cause the transition to fail, the object to remain in its original state, and the exception to display to the user. 指派脚本给某个转换时,有两种选择: before 和 after 。就像名字所说的,设置为 before 的脚本,会在转换之前运行。这非常适合需要在转换运行之前检查某些事情是否发生的情形,比如测试另一个相关对象或页面已经被上载,或者没有拼写错误。设置为 after 的脚本,在转换完成后马上运行 - 尽管有时脚本会抛出为捕获的例外,它将导致转换失败,对象仍将保存在其原始状态,该例外会显示给用户。 编辑工作流表达式Throughout this chapter you've seen values that can be expressed as workflow expressions. For example, the value assigned to a variable is the result of a workflow expression. This expression is nothing special; it's merely a Template Attribute Language (TAL) expression with a few different variables available. You already learned about TAL expressions in Chapter 5, so you should be familiar with these expression and all their options, such as Python, string, and path expressions. 本章的整个部分中,你已经看到值可以表示成工作流的表达式。例如,指派给某个变量的值时一个工作流表达式的结果。该表达式没有什么特殊的地方;它只是一些 带有不同变量的TAL(页面属性语言)表达式。在第五章中,你已经学过TAL表达式,你应当熟悉这些表达式和他们的选项,例如 Python, string 和路径表达式。 Unlike the standard TAL expression, a few extra parameters are passed through to the namespace, relating to the particular workflow. The namespace for a workflow expression contains the following: 与标准TAL表达式不同,有几个附加的、与该工作流相关的参数被传递到这里的名字空间。工作流表达式的名字空间包含:
常见应用和例子I'll now present some common tasks you can achieve easily using workflow. When a user causes a workflow transition, this transition runs using that specific user's account. In many of these examples, a normal user may not have the correct permissions to perform the task. For example, members don't normally have the right to access the list of members unless this permission has been explicitly given to them. 我现在要讲讲使用工作流可以轻松实现的几个常见的应用。在某个用户进行一次工作流转换时,该转换使用这个用户的权限来执行。在许多情况下,普通用户没有执行该任务的权限。例如,各个成员通常没有列出成员的权限,除非显式给定该权限给他们。 To solve this permission issue, where noted, some of the following Script (Python) objects have been given a slightly different role. To set a proxy role on a script, access the Proxy tab on an object and then select the user to run the script, as shown in Figure 8-9.
Figure 8-9. Setting proxy settings on a script You would, of course, make sure your scripts executed with the minimum roles needed, depending exactly upon what your script does. 当前,你应当确认的是,让你的脚本以所需的最低的权限执行,这取决于你的脚本要干些什么事情。 介绍工作流表达式The following are some useful examples of workflow expressions that can be used in various places. 以下是一些有用的工作流表达式的例子,他们可以应用在许多地方: To get the comments, or an empty string, with this transition, use the following: 要为此次转换取得注释,或者空字符串,用下面的工作流表达式: python:state_change.kwargs.get('comment', '') To obtain the title of the folder that the object is in, use this: 要获得该对象所处容器的标题,用这个: container/Title To test if the old state is review state, use this: 要测试原先状态是否处于review状态,用这个: python: state_change.old_state == 'review' To get the user executing this transition, use this: 要获得执行该此转换的用户,用这个: user/getId So if you wanted to track who the last user to transition an object was, you could add a last user variable into the workflow. You do this by going to the workflow and clicking the Variables tab. Then add the variable last_user. If you set the Default expr variable to user/getId, each time the object changed, that value would be stored for you. 如果你想跟踪最后一次转换某个对象的用户是谁,你可以在工作流中添加一个 last user 变量。方法如下:进入工作流,点击变量标签。加入变量 last_user 。如果设置 Default expr 变量为 user/getId , 则每次该对象修改时,其值会被保存起来。 使用工作流跟踪内容改动For one particular application a client of mine wanted to keep track of every time an item was edited and any reasons for that edit so that when auditing the item later, there would be a comment for each change. Thanks to workflow, this was quite easy to achieve. 对于某个具体的应用来说,我的一个客户要跟踪一个对象每次被编辑的过程,以及编辑的原有,这样之后的审计工作可以看到每次修改的说明。由于工作流的作用,这很任意实现。 In this case, the workflow had only one state-but actually this will work for almost any workflow. To this one workflow, a transition was added called edit. That transition didn't actually change the object's state; the destination state for that transition was (Remain in state), meaning no change occurred. 在这种情形下,工作流只有一个状态-不过这对于任何工作流都是可用的。对于这个工作流,我们加入一个名为 edit 的转换。该转换并不修改对象的状态;该转换的目标状态时 (Remain in state) ,表示不会进行改变。 When an object is edited, a method is called to perform the change. For example, when a document is edited, the method called is document_edit.cpy. You can find that script by clicking portal_skins, clicking plone_form_scripts, and clicking document_edit. All that's needed is to add one line to that script before the last line: 在一个对象被编辑时,都会有一个方法被调用,以执行修改。例如,当一个页面文档被编辑时,被调用的方法时 document_edit.cpy 。点击 portal_sins ,点击 plone_form_scripts ,然后点击 docuemnt_edit , 可看到这个方法。 我们要做的是在这个脚本最后一行之前加入一行: context.portal_workflow.doActionFor(new_context, 'edit', comment='') The doActionFor method of portal_workflow performs the transition given (in this case, edit) for the object passed in (in this case, context). Each time the object is edited, that edit transition will fire. That will cause a line to be added to the comments list showing who edited the object, when it was added, and any comments associated with it. portal_workflow 的这个 doActionFor 方法, 对传入的对象(在这里是 context )执行给定的转换(在这里是 edit )。每次该对象被编辑是,都会进行 edit 转换。这会导致添加一行显示谁编辑了该对象、何时添加、以及任何相关的注释。 When an object is edited, there are actually no comments, so to be a little more advanced, you'd have to modify the document's edit template to include a comments field. You could then access this comments list by going to the State tab, where the list of changes displays at the bottom. 当某个对象被编辑时,实际上并没有注释信息,因此,为了更优化些,你得修改页面文档的编辑模板,让它包括一个注释域。之后,你就可以进入状态标签来访问该注释信息列表,其中修改列表显示在页面下方。 移动对象One useful ability is moving an object during the workflow. For example, you could move all press releases into a folder called Press Release each time you publish one. Content could be created and edited anywhere and then on publishing moved into that folder. The example script in Listing 8-1 moves the object being workflowed into the Members folder. To add this script, go into the workflow tool in the ZMI, and select the Scripts tab. Then select Script (Python) from the drop-down box. Give the new object the name moveObject, and then enter Listing 8-1 into this script. 工作流的一个有用功能是在工作流过程中移动一个对象。例如,你可以在每次发布时,把所有的出版发行对象放入名为 Press Release 的文件夹中。内容可以在任何地方创建和编辑,然后在发布时移到那个文件夹中。表8-1的脚本例子把工作流工作中的一个对象移入 Members 文件夹。 要加入这个脚本,在ZMI中进入工作流工具,然后选择脚本页签,从下拉框中选择脚本,把它命名为 moveObject , 然后输入表8-1的内容到该脚本中。 Listing 8-1. Moving an Object 列表8-1. 移动一个对象 ##parameters=state_change # get the object and its ID obj = state_change.object id = obj.getId() You need to do a few more things; first, assign this script to a transition. I'd normally use such a script in the publish transition. To do this, go to that transition and assign the value of script (after) to moveObject. 你还需要再做些事情;首先把这个脚本指派给一个转换。我通常把该脚本用在发布转换中。方法如下:进入转换,指定 script (after) 的值为 moveObject 。 Second, one other small problem exists: This script moves objects into the Members folder. You'll probably have a better destination in mind, of course. To perform such a move, a user has to have the appropriate rights to move objects between these folders. Normally, only a manager can move objects into the Members folder. So you need to give the script the proxy role of manager. You can do this by clicking Scripts, clicking moveObject, and selecting the Proxy tab. Assign the role of manager to this script. You can find more information about security and local roles in Chapter 9. 第二,存在另一个小问题:这个脚本把对象移到 Members 文件夹中。当然,你可能有另一个更好的目标。要进行这样的移动,用户必须具有在这几个文件夹间移动对象的权限。通常,只有管理员能够把对象移到 Members 文件夹。 因此,你需要给这个脚本管理员的代理角色。方法如下:点击脚本,点击 moveObject, 选择Proxy页签。指定管理员角色。第九章有更详细的关于安全和本地角色的内容。 Looking at the code, first the script gets the object and the object's ID from the transition namespace. Then it gets the source and destination folders. Then it utilizes Zope's ObjectManager Application Programming Interface (API) to perform the copy and paste. You could, of course, determine these folders programmatically-perhaps based on the user performing the transaction or on the type of content being moved. Finally, you get the object and pass it to an exception ObjectMoved. 看看这个代码,这个脚本首先从转换的名字空间中获取这个对象及其ID。然后获取源文件夹和目标文件夹。然后用Zope API中的 ObjectManager 进行复制和粘贴。当然,你可以根据执行该转换的用户或被移动的内容类型,在程序中决定这些文件夹。最后,你获得了这个对象,并把它传递给 ObjectMoved 表达式。 The ObjectMoved exception is a special exception to DCWorkflow. By passing the new object twice as parameters into the exception, the new object will be passed up to the Plone front end. This is critical so that when the user is sent to the object in response to the change, it's to the new location of the object, not the old one. Of course, you may want to write a function that moves the function back after rejecting the object, perhaps to the member's home folder. 这个 ObjectMoved 表达式是一个DCWorkflow的特殊表达式。把这个新对象作为参数,两次传递到例外中,新对象将被传到Plone的前端。这很重要,这样在对改变响应时,用户被发送给这个对象。你要写一个在拒绝该对象时,能够把该功能返回的函数,可以返回在成员的根文件夹下。 Another special case, and a more unusual one, is to delete an object in workflow. Usually deleting an object is an action from the containing object, so it's unusual to see in workflow. For this task, you can raise an ObjectDeleted exception. Listing 8-2 shows the script to perform a delete. 另一个更少用到的、特殊的情况,是在工作流中删除某个对象。通常删除对象是该对象容器的一个操作,这在工作流中很少见。对这样的操作,你可以抛出一个 ObjectDeleted 例外。列表8-2显示了执行删除的脚本。 Listing 8-2. Deleting an Object 表8-2. 删除一个对象 ##parameters=state_change # get the object obj = state_change.object id = obj.getId() You could call this script deleteObject and successfully delete objects in the workflow. Again, by ensuring the error is raised, Plone will know what to do; in this case, it takes the user to the folder containing that object. 你可以把这个脚本叫做 deleteObject ,而且在工作流中可以成功删除对象。再强调一次,要确保抛出错误,这样Plone才会知道怎么做;在本例中,他会把用户带到包含该对象的文件夹中。 发送通知邮件If you have a Web site that a user doesn't visit regularly, then putting information on the site about what has to be reviewed and when is rather pointless. You can turn workflow into a rudimentary notification system by using it to send e-mails to the users. The notification channel of e-mail is just one simple example; this could also be an instant message, a text message delivered to a phone, and so on. I'll leave other options to your imagination. 如果你有一个用户不会有规律地访问的网站,把关于什么东西需要审核、何时审核的信息发在这个网站中,是没有意义的。你可以把工作流专访成一个通知系统,用 它来发送邮件给用户。邮件的通知是一个简单的例子;也可以是一个即时消息,一串发送到电话上的文本信息,等等。你可以自己想像一下其他的选项。 In this example, you'll send e-mail via the MailHost object on the server to every user who has the reviewer role in the system, telling them about a new item that has been submitted for review. This is actually a more complicated script than the ones I've shown you so far, since it runs through a few steps: defining the variables, finding the account name of every reviewer, finding an e-mail, and sending an e-mail. Listing 8-3 shows the script. 在本例中,你可以通过服务器上的 MailHost 对象给系统中具有 reviewer身份的用户发送邮件,告诉他们有一个新内容条目已经提交等待审核。这比之前看到的脚本要复杂的多,因为它要经过好几个步骤:定义变量,找到每个审核员的帐户名,找到邮件、发送邮件。表8-3给出了这个脚本代码。 Listing 8-3. Sending an E-Mail Notification 列表8-3. 发送eMail通知 ##parameters=state_change # the objects we need object = state_change.object This sets up the message and objects you need. Apart from the object being transitioned, you'll also need a reference to the membership tool portal_membership and the Simple Mail Transfer Protocol (SMTP) server via MailHost. The message is easily configurable to send an e-mail in any format you like. 这个脚本设置你需要的信息和对象。处理要被转换的对象以外,你还需要引用到一个成员工具 portal_membership 和一个通过 MailHost 引用的SMTP服务器的参考。 消息可以改为你想要的任何格式。 You then use the listMembers method of the portal_membership object to get a list of members. For each member, you can then see if the reviewer role is in the list of roles for that user by calling the getRoles method: 之后,你用 portal_membership 对象的 listMembers 方法获得成员列表。 对于每个成员, 你可以调用 getRoles 方法来查看该用户是否列在审核员角色的列表中。 for user in mship.listMembers(): if "Reviewer" in mship.getMemberById(user.id).getRoles(): The astute reader will note that looping through every member in a Plone site could be a little slow if you have thousands of users. In the next chapter, you'll modify this script to pull the list of users from a specific group. 聪明的读者会发现,如果网站有几千个用户,查找Plone站点中的每个成员会相当慢。下一章,你可以把这个脚本该为从某个指定用户组中提取用户列表。 There's no point in sending an e-mail if you don't have a user's e-mail address, so you check here that there's a valid e-mail first. Now all that's left is to format the e-mail and send it. For this you can use Python's string replacement functionality and pass in four parameters that correspond to the %s in the message variable set at the beginning of the script. After this replacement, the msg variable will contain the e-mail you want to send. To send the e-mail, simply call the send method of the MailHost and pass through the e-mail string: 如果没有用户的邮件地址,发送邮件就没有意义了,因此首先检查有一个有效的电子邮件。剩下来的就是邮件格式化,并发送。用Python的字符串替换函数可以完成这样的工作,给脚本的开头设置的 message 变量传入4个 %s 参数, msg 变量包含你要发送的电子邮件。要发送这封电子邮件,只要简单地调用 MailHost 的 send 方法,并传入表示邮件的字符串。 if user.email: msg = message % ( administratorEmailAddress, user.email, This will result in the following e-mail being sent: 这样会把下面的邮件发送出去: From: administrator@agmweb.ca To: andy@agmweb.ca Subject: New item submitted for approval Appendix B shows the full listing for this script. 附录 B,列出了该脚本的完整代码 使用PloneCollectorNGPloneCollectorNG is a bug tracker that's available for Plone. You'll find many other issue trackers out there, but this is the one I use and recommend for Plone. In fact, writing an issue tracker seems to be a common thing for developers to do. One of the really nice things about workflow is that it enables your users to significantly change the way an application works. As a developer, developing products hooking into DCWorkflow allows your application to remain flexible. You can find PloneCollectorNG at http://www.zope.org/Members/ajung/PloneCollectorNG. PloneCollectorNG是Plone中的错误追踪系统。有许多种错误追踪器产品,不过我自己使用并推荐使用的是 PloneCollectorNG。 事实上,编写一个问题追踪器常常是开发人员都要做的事。工作流的一个非常好的事情是让用户能够改变应用的工作方式。作为一个开发人员,开发应用 DCWorkflow的产品可以让你的应用保存灵活性。PloneCollectorNG可以在 http://www.zope.org/Members/ajung/PloneCollectorNG 中找到。 The product adds a series of content types during installation; one of them is PloneIssueNG, which is an issue (or bug report). Rather than hard-coding exactly how the issue moves through the database, a separate workflow is assigned to the issue. That workflow contains appropriate states, transitions, variables, and worklists. 这个产品在安装时会新建一系列的内容类型,其中之一是 PloneIssueNG, 它就是一个 issue (或出错报告)。 这个issue没有使用硬编码来完成如何在一个数据库中移动问题,它使用了一个独立的工作流。这个工作流包含需要的状态、转换、变量和工作列表。 At any stage you can find out what state an object is in by calling the getInfoFor method of portal_workflow. This useful method accepts an object and the variable to be looked up. In PloneCollectorNG's workflow, that variable is called state, and in Plone workflow, it's called review_state. For example, to find the state for an object, you use this: 任何阶段,你都可以调用 portal_workflow 的 getInfoFor 方法来找到某个对象是什么状态。这个有用的方法接收一个对象及要查看的变量作为参数。在 PloneCollectorNG的工作流中,该变量称为 state*, 在Plone工作流中,它叫做 *review_state 。 例如,要找到某个对象的状态,可用: portal_workflow.getInfoFor(obj, "state") You can find possible states for an object by examining the state's object directly from the workflow, like so: 你可以直接从工作流中检查状态对象来找到一个对象可能的状态。 portal_workflow['pcng_workflow'].states._mapping.keys() The result of this is that if your user wants to have a simple issue-tracking system, then modifying this workflow through the Web is relatively trivial (if, when the application was developed, the workflow tools have been considered). Compare this to another popular bug-tracking system, Bugzilla, where changing a state or a transition requires hours and hours of a Perl programmer's time to find all the hard-coded references to a bug's state. 结果是如果你的用户需要一个简单的问题追踪系统,通过Web来修改这个工作流是非常容易的(如果在开发应用程序时就考虑使用工作流工具的话)。比较一下另 一个常用的错误追踪系统-Bugzilla,在修改状态或转换时,会花费一个Perl程序设计人员大量的时间来找到对某个错误状态的所有的参考(它是被硬 编码的)。 编写和发布工作流If you've got a great workflow for your application, you have a couple of different ways to write and distribute workflow. The following sections close the discussion of workflow by presenting a couple of these options. 如果你的应用程序已经有了一个很好的工作流,在编写和分发工作流时会有一些困难。下面的部分讲述工作流在这方面的选项来结束对工作流的讨论。 通过ZMI来编写工作流Probably the simplest but most laborious way to write workflow is to use the ZMI. Although the ZMI drives many people crazy, it's a simple way to set up the options. Unfortunately, once you've started writing through the ZMI, you're stuck in that paradigm. In other words, there's no easy to edit or alter that workflow on the file system. I discussed editing a workflow through the Web with you earlier in this chapter, of course. 编写工作流最简单、但最辛苦的方式是通过ZMI。尽管ZMI让许多用户发疯,它是设置选项的最简单的方法。不幸的是,一旦你用ZMI开始编写,你就被限制 在这样的方式下了。换句话说,没有可以在文件系统中进行简单编辑或修改工作流的办法。之前我讨论的办法都是通过Web来编辑工作流的。 To export a workflow from the ZMI, click portal_workflow and select the Contents tab. Select the created workflows you'd like to export by checking the boxes on the left of the ZMI, and then click import/export. At the top part of the export page, select Download to local machine, and click export. A file with extension .zexp will be created that can be saved and redistributed. Selecting XML Format will provide a file in Extensible Markup Language (XML) format with an .xml extension. 要从ZMI中导出一个工作流,点击 portal_workflow , 选择Contents页签,选择要导出的已建好的工作流,点击 import/export 按钮。在导出页面的顶部,选择 Download to local machine , 点击 export 。这样会创建一个可保存、克分发的后缀名为 .zexp*的文件。选择XML格式会生成一个后缀名为.xml* 的XML格式的文件。 If you're provided a workflow in a the .zexp or .xml format, then importing the workflow into your Plone is straightforward. Place that file in the import directory of Zope on the file system. This can be the instance home directory or the Zope directory. 如果你有一个 .zexp 或 .xml 格式的工作流,导入这个工作流是非常直接的。 只要把这个文件放到Zope文件系统的import目录。这个import目录在Zope实例的根目录下。 Then click portal_workflow, select the Contents tab, and click import/export. At the bottom part of the page, you'll see a small form that takes an import filename. Enter the name of the filename there, and leave Take ownership of imported objects selected. Click the Import button to import the workflow. The workflow will now be imported and given the name specified in the export. 然后点击 portal_workflow , 选择Contents页签,点击 import/export 。在页面底部,有一个导入文件名的小表单。输入文件的文件名,选择 Take ownership of imported objects 。点击 Import 按钮就可以导入这个工作流。这个工作流就被导入了,并且被命名为导出时候设置的名称。 用Python来编写工作流Using Python is probably the favorite way of programmers to write a workflow, since it can all be done in Python and easily distributed. First, make a Python module on the file system. At the top of the file, import the appropriate tools, as follows: 程序设计人员最喜欢使用Python来编写工作流,因为使用Python什么都可以完成,而且分发容易。首先,在文件系统中构建一个Python模块。在文件的头部,导入需要的工具,方法如下: from Products.CMFCore.WorkflowTool import addWorkflowFactory from Products.DCWorkflow.DCWorkflow Second, make a function that creates the workflow. Appendix A lists the API for writing a workflow in a little more detail. But you could just cheat and look at all the great examples available in the PloneWorkflow's project in the collective (http://sf.net/projects/collective), or even the ones contained in Plone. For example: 然后,建一个创建工作流的函数。附录A 列出了编写工作流的API的详细资料。你给参看 PloneWorkflow 中的代码。或者Plone自带的代码。例如: def sample(id): """ Sample workflow """ ob = DCWorkflowDefinition(id) Finally, register the workflow in the system, like so: 最后,在系统中注册这个工作流,方法如下: addWorkflowFactory(sample, id='sample_workflow', title='Sample workflow') This script will need to be as part of a product installation. Chapter 12 covers writing and installing products. 这个脚本会作为产品安装的一部分。第十二章介绍了编写和安装产品的技术。 Now, of course, a shortcut is available, which is called DCWorkflowDump. This will take the code from the ZMI and dump it into a Python module for you. You can find the source code for DCWorkflowDump in the collective at http://sf.net/projects/collective, but you can also find a zip file of the code on the Plone book Web site at http://plone-book.agmweb.ca. 现在有一个快捷的方式可用,即 DCWorkflowDump*。 它从ZMI中提取代码,然后把它导入到一个Python模块中。在http://sf.net/projects/collective中可以找到 *DCWorkflowDump 的代码。 To install DCWorkflowDump, unzip the file and copy the directory called DCWorkflowDump into the Products directory of your Plone installation. To check that you're in the right directory, your Products directory should also contain a directory for DCWorkflow, among other things. Then restart your Plone instance. 要安装 DCWorkflowDump ,解压这个文件,复制到Plone实例的产品目录。然后重启Plone实例。 Once you've restarted Plone, go to the particular workflow in the ZMI, and you'll notice a new tab called dump. Click that page to get the dump screen, and then click Dump it! to dump the workflow to the screen. This will take your workflow and format it in Python for you. Save that file to your product, and you now have a Python file you can manipulate. This product is a great tool because it allows you to create the workflow in the ZMI and then distribute and alter it through Python. 重启Plone后,进入ZMI中指定工作流,你会注意到有一个新的、名为 dump 的页签。点击后进入dump页面,点击 Dump it! 会把工作流dump到屏幕上。这会把你的工作流放入Python模块中。保存该文件,你就有了可用的Python文件。这个产品很好,它让你能够在ZMI中创建工作流,然后用Python来分发。 |








