65.9K
CodeProject 正在变化。 阅读更多。
Home

为 SharePoint 创建版本流

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2019 年 6 月 28 日

CPOL

8分钟阅读

viewsIcon

4677

以下是我使用 Microsoft Flow 和 SharePoint Online 进行的一个实验,用于在文档更改时访问版本信息

背景

我通常认为,在大多数情况下,当我们谈论内容管理时,记录应与文档分开。文档通常是在协作过程的一部分创建的,而记录通常是在合规过程的一部分创建的。为了尝试支持这一原则,我尝试使用 SharePoint 进行一些模拟,将文档的主要版本发送到另一个系统(在本例中为电子邮件),以最小的用户交互来模拟记录保存过程。

问题是,SharePoint 无法轻松公开文档版本信息。我尝试搜索了一下,但没有找到太多有帮助的信息。这时 Microsoft Flow 就派上用场了。

Microsoft Flow

Microsoft Flow 是一个低代码工作流工具,可以连接到 SharePoint Online,功能相当强大。使用 Flow,我着手设计了一个工作流,该工作流将监视 SharePoint Online 文档库,并在发布主要版本时采取行动。但是,要做到这一点,我需要能够获取文件的版本信息。解决方法基本上是使用 SharePoint Online API 在文档更改时检索版本信息,并在版本为主要版本更改时根据该信息采取行动。让我们深入了解工作流是如何构建的。

步骤 1 - 文件更改触发器

Step 1 - File Change Trigger

第一步是监视 SharePoint 的文件更改。将其添加为起始触发器,并提供您要管理的站点和文档库。

步骤 2 - 获取文件元数据

Step 2 - Get File Metadata

接下来,我们添加一个操作来获取文件元数据。再次提供相关站点,并添加从触发器传递的动态“文件标识符”对象。

步骤 3 - 获取文件属性

Step 3 - Get File Properties

最后,我们添加一个操作来获取文件的属性。这次,我们再次指定站点和文档库,并将已更改文件的 ItemID 传递过去。

步骤 4 - 发送 HTTP 请求

Step 4 - Send HTTP Request

现在到了比较棘手的部分。我们在“发送 HTTP 请求”操作中使用从前面步骤收集的信息来检索 SharePoint 存储的有关文件的某些属性。再次指定我们正在使用的站点,将请求类型设置为 GET,并使用以下 API 端点来检索文档属性:

_api/web/GetFolderByServerRelativeUrl('$FolderPath')/Files('$FileName')

确保您将 $FolderPath 替换为动态的“文件夹路径”对象,将 $FileName 替换为动态的“带扩展名的文件名”对象。

注意:之前,我使用以下端点来检索与文件相关的所有版本。最近,有人指出该端点不包含文档的当前版本。我不确定这是否是最近更改的,还是我遗漏了。

_api/web/GetFolderByServerRelativeUrl('$FolderPath')/Files('$FileName')/Versions')

步骤 5 - 解析 JSON

Step 5 - Parse JSON

HTTP 请求操作将返回一个 JSON 对象,我们现在需要对其进行解析,因此添加一个“解析 JSON”操作,并指定上一个操作中的“Body”对象。在提供架构方面,您有两个选项。首先,您可以将流运行到步骤 4,复制返回的结果,然后单击“使用示例载荷生成架构”选项来定义架构。或者,您可以使用我生成的架构,这应该是 SharePoint Online 的标准、开箱即用的架构(截至本文撰写之时)。

{
    "type": "object",
    "properties": {
        "d": {
            "type": "object",
            "properties": {
                "__metadata": {
                    "type": "object",
                    "properties": {
                        "id": {
                            "type": "string"
                        },
                        "uri": {
                            "type": "string"
                        },
                        "type": {
                            "type": "string"
                        }
                    }
                },
                "Author": {
                    "type": "object",
                    "properties": {
                        "__deferred": {
                            "type": "object",
                            "properties": {
                                "uri": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                },
                "CheckedOutByUser": {
                    "type": "object",
                    "properties": {
                        "__deferred": {
                            "type": "object",
                            "properties": {
                                "uri": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                },
                "EffectiveInformationRightsManagementSettings": {
                    "type": "object",
                    "properties": {
                        "__deferred": {
                            "type": "object",
                            "properties": {
                                "uri": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                },
                "InformationRightsManagementSettings": {
                    "type": "object",
                    "properties": {
                        "__deferred": {
                            "type": "object",
                            "properties": {
                                "uri": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                },
                "ListItemAllFields": {
                    "type": "object",
                    "properties": {
                        "__deferred": {
                            "type": "object",
                            "properties": {
                                "uri": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                },
                "LockedByUser": {
                    "type": "object",
                    "properties": {
                        "__deferred": {
                            "type": "object",
                            "properties": {
                                "uri": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                },
                "ModifiedBy": {
                    "type": "object",
                    "properties": {
                        "__deferred": {
                            "type": "object",
                            "properties": {
                                "uri": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                },
                "Properties": {
                    "type": "object",
                    "properties": {
                        "__deferred": {
                            "type": "object",
                            "properties": {
                                "uri": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                },
                "VersionEvents": {
                    "type": "object",
                    "properties": {
                        "__deferred": {
                            "type": "object",
                            "properties": {
                                "uri": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                },
                "Versions": {
                    "type": "object",
                    "properties": {
                        "__deferred": {
                            "type": "object",
                            "properties": {
                                "uri": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                },
                "CheckInComment": {
                    "type": "string"
                },
                "CheckOutType": {
                    "type": "integer"
                },
                "ContentTag": {
                    "type": "string"
                },
                "CustomizedPageStatus": {
                    "type": "integer"
                },
                "ETag": {
                    "type": "string"
                },
                "Exists": {
                    "type": "boolean"
                },
                "IrmEnabled": {
                    "type": "boolean"
                },
                "Length": {
                    "type": "string"
                },
                "Level": {
                    "type": "integer"
                },
                "LinkingUri": {
                    "type": "string"
                },
                "LinkingUrl": {
                    "type": "string"
                },
                "MajorVersion": {
                    "type": "integer"
                },
                "MinorVersion": {
                    "type": "integer"
                },
                "Name": {
                    "type": "string"
                },
                "ServerRelativeUrl": {
                    "type": "string"
                },
                "TimeCreated": {
                    "type": "string"
                },
                "TimeLastModified": {
                    "type": "string"
                },
                "Title": {
                    "type": "string"
                },
                "UIVersion": {
                    "type": "integer"
                },
                "UIVersionLabel": {
                    "type": "string"
                },
                "UniqueId": {
                    "type": "string"
                }
            }
        }
    }
}

此载荷和 JSON 解析为我们提供了许多有用的变量,包括主要和次要版本号。

深入探讨

为了更进一步,以下是一些可选步骤,我添加这些步骤来确定文档是否为主要版本(x.0),如果是,则模拟一个“将文件保存为记录”的电子邮件来证明该过程。

步骤 6 - 只处理主要版本

Step 6 - Only work with Major Version

我只想处理主要版本,因为从这个工作流的角度来看,我将主要版本保存为记录实例。因此,让我们添加一个条件来检查最新版本是否为主要版本,方法是检查 JSON 解析中的次要版本变量是否设置为 0

步骤 7 - 示例动态属性

Step 11 - Example Dynamic Properties

Flow 的最后一个步骤显示了一个电子邮件操作,其中包含一系列您可以使用的动态内容,这些内容将在 Flow 的末尾使用。在此示例中,我将向文件创建者发送一封电子邮件,其中包含有关已发布版本的信息、在 SharePoint Online 中运行的发布命令附带的任何注释,以及附件到电子邮件中的文件。

奖励!- 将版本号保存到文档属性

在此原始帖子的评论中,Eyo Sama 和 Dave Albrecht 在将版本号保存到文档以便在文档本身中使用时遇到了一些问题。让我们来扩展上面的 Flow,创建一个 status 字段来保存当前版本。在 SharePoint 中,添加一个新列(我称之为 status)来保存版本标签。添加新列后,它将在 Word 的文档属性中可用,并可用于“快速部件”之类的函数。

奖励步骤 1 - 锁定布尔值

Bonus Step 1 - Locked Boolean Variable

我们需要做的第一件事是创建一个变量来测试“锁定使用中”问题。因为我们将更新文档,所以我们需要确保它不会被锁定编辑。最初将此变量设置为 true

奖励步骤 2 - 循环

Bonus Step 2 - Do until loop

接下来,添加一个 do until 循环,以便我们可以在文档被锁定时重试将版本添加到文档属性。

奖励步骤 3 - 作用域和文档签出

Bonus Step 3 - Document checkout in a scope

循环中的第一个操作是尝试执行文档签出,以便我们可以在不创建新版本的情况下更新文档属性。我们希望在作用域内尝试签出此文档。Microsoft Flow 中的作用域允许我们实现 Try/Catch 逻辑,也就是说,我们可以尝试执行一系列任务并输出这些任务的结果。在这种情况下,我们执行一个 HTTP Post 请求来签出文档,因此再次指定我们正在使用的站点,将请求类型设置为 POST,并使用以下 API 端点来签出文档:

_api/web/GetFolderByServerRelativeUrl('$FolderPath')/Files('$FileName')/CheckOut()

奖励步骤 4 - 检查结果

Bonus Step 4 - Check the result

现在让我们检查 scope 语句的结果。我们通过检查我们使用 if 语句和以下动态表达式创建的 scope 的结果来做到这一点:

result('Scope')[0]['status']

上面语句中的 Scope 指的是我们在上一步中添加的 Scope 语句的名称。

奖励步骤 5 - 即使失败也要继续运行

Bonus Step 5 - Keep runing

默认情况下,Microsoft Flow 会在流中的某个项目失败时停止处理。因为我们对此有计划,所以我们需要将 if 语句设置为即使 Scope 组失败也要运行。单击 if 语句标题栏上的三个点 (…),然后选择“配置运行后操作”,并确保所有退出状态都已勾选。

奖励步骤 6a - 成功!更新版本

Bonus Step 6a - Update the version

如果作用域成功,那么我们已经签出了文件。如果我们添加“更新文件属性”项,使用我们正在处理的站点和库,并指定 itemId,您应该还会看到与文档库关联的任何其他文档属性。如您所见,我库中的状态文档属性显示出来,我已向该属性添加了版本标签。

奖励步骤 6b - 成功!重新签入

Bonus Step 6b - Check the version

现在我们已经填充了版本属性,让我们使用另一个 HTTP 命令将其重新签入。再次指定我们正在使用的站点,将请求类型设置为 POST,并使用以下 API 端点来签入文档:

_api/web/GetFolderByServerRelativeUrl('$FolderPath')/Files('$FileName')/CheckIn(checkintype=2)

我们使用签入类型 2 来签入文档,而无需增加版本号。供您参考,类型 0 是增加次要版本,类型 1 是增加主要版本,类型 2 是覆盖且版本不变。

奖励步骤 6c - 成功!关闭循环

Bonus Step 6c - Close the loop

最后,我们通过将 lock 变量设置为 false 来关闭循环。这确保我们不会一直循环并重复工作。

奖励步骤 7 - 处理失败

Bonus Step 7 - Handle the failure

让我们处理文档被打开编辑或签出的情况下的失败状态。首先,创建一个 if 语句来检查我们尝试签出文档的次数。我们这样做是因为我们不希望 Flow 无限循环。我将我的迭代次数设置为 20。如果迭代次数等于或大于 20,则将 Is Locked 变量设置为 false。这将中断我们的循环并基本上关闭 Flow。如果您愿意,也可以在此处发送警告,但我假设如果在尝试 20 次后仍无法更新,则有人仍在更改文档,并且将会有另一次保存。如果我们还没有达到迭代限制,让我们添加一个延迟,这样我们就不必每隔几秒/几分钟就尝试一次。在这种情况下,我添加了五分钟的延迟。根据您的用户,您可以根据需要增加或减少此值。

后续步骤

所以,从头到尾,这就是(非奖励部分的)完整工作流。

Complete Workflow

如果这是一个生产环境的交付项,例如,我们可以使用此 Flow 并添加一个操作来调用录制保存系统的 API,通过 HTTP POST 将文档和收集的元数据发送出去,从而独立于用户的交互来保存记录。或者我们可以执行任何其他类似的操作。

历史

本文已更新,以反映使用版本端点时遇到的一些问题,并发布版本数据回文档属性。

© . All rights reserved.