如何限制编辑范围?如何将编辑限制在某些边界?如何将用户限制为仅在分配给他们的工作订单边界内进行编辑?是否可以限制用户在某些边界中进行编辑,而不能在其他边界中进行编辑?我们经常遇到这些问题,在本博客中,我将说明如何使用属性规则来做到这一点。
一、限制边界区域内的编辑内容
在本例中,我们希望创建一个边界要素类,该要素类将表示限制区域或区域。我们还将创建另一个表示数据的要素类;最后,我们将向要素类添加一个属性规则,用于检查正在创建或更新的要素是否在边界内。
注意: 此示例可在装有 ArcGIS Pro 2.4 或 GeoScene Pro任意版本的产品 以及更高版本的文件地理数据库中完成。但是,我使用的是企业级地理数据库。因为后续想要发布可编辑的要素服务。当数据源为文件型地理数据库时,无法发布可编辑的要素服务。
在企业级地理数据库中,使用如图所示的字段创建以下两个要素类。
右键pointClass 数据设计 - 属性规则,在约束属性规则中,添加一条约束属性规则,填写名称描述和表达式,还有编写错误提示,勾选使其在插入、更新和删除时执行,然后单击保存。
使用以下脚本
//仅允许在边界内进行编辑
var fsBoundary = FeatureSetByName($datastore, "boundaryClass", ["globalId"], false);
return Count(Intersects(fsBoundary, Geometry($feature))) > 0
让我们测试一下它出来,在boundaryClass中创建面,然后尝试在边界外部和内部创建点要素。
二、将编辑限制为用户分配的边界
所以上面的例子非常简单明了。有一个或多个边界,你希望所有用户确保在边界内进行编辑。如果更进一步考虑,是否可以使用属性规则允许某些用户仅在管理者为其分配的边界内进行编辑?在上面的例子的基础上,我们将找出如何做到这一点。请注意,您还可以将相同的想法应用于外业工作和上门工作的订单。
此示例可通过 ArcGIS Pro 2.5或GeoScene任意版本的产品 和与企业级地理数据库(Enterprise Geodatabase)的客户端/服务器连接来完成,该数据库已注册到服务器。我正在通过服务使用 ArcGIS Enterprise 11.1,用GeoScene Enterprise也能完成。
首先,我们需要一个额外的表,其中为用户分配了边界。创建一个 usersBoundary 表,其中包含一个用户名的文本字段和一个boundaryGuid 字段表示外键到 boundaryClass 的 globalId。我们还将在 boundaryClass 和 usersBoundary 表之间创建一个关系类。您不必创建关系,但它将允许我们将多个用户分配到边界,并简化在 Pro 中编辑表格的过程。
我们在 pointClass 上需要的最后一件事是启用编辑器跟踪。 这就是我们如何通过查看 $feature.last_edited_user 来判断哪个用户实际上正在对属性规则进行编辑。右键要素类,管理,开启编辑者追踪。
好的,目前已经万事俱备,让我们将用户分配到边界,如下所示:
许工(xugong)只能在边界'金泰大厦区域'中编辑
张工(zhanggong)仅在边界'老国展区域'中编辑
谢工(xiegong)只能在边界'和平里区域' 中编辑
让我们将 pointClass 上的属性规则表达式编辑为以下脚本。
//获得当前用户
var user = $feature.last_edited_user;
//获取创建/更新要素的当前边界
var fsBoundary = FeatureSetByName($datastore, "boundaryClass", ["globalId", "name"], false);
var fsIntersectedBoundaries = Intersects(fsBoundary, Geometry($feature))
//如果不在任何工作区内则报错
if (Count(fsIntersectedBoundaries) == 0)
return {"errorMessage": "要素必须创建在工作区内"}
//我们只对第一个相交的工作区感兴趣
//我们可以增强这个脚本去遍历所有工作区
var boundary = First(fsIntersectedBoundaries);
var boundaryGlobalId = boundary.globalId;
//查询usersBoundary类(表)
var usersBoundary = FeatureSetByName($datastore, "usersBoundary");
//用户被允许在当前工作区吗?
var usercanEdit = Count(Filter(usersBoundary, "username = @user AND boundaryGuid = @boundaryGlobalId")) > 0
var bid = boundary.boundaryId
//返回一个友好的提示
if (usercanEdit == false)
return {"errorMessage": "用户" + user + " 未被授权编辑区域 " + bid }
return usercanEdit;
在正式使用之前。我们还要引用注册的数据源,发布要素服务到GeoScene Enterprise 或 ArcGIS Enterprise。以便使用许工、张工这样的用户在web端的身份信息,而不是使用连接sde的数据库的用户。数据库用户往往数量很少且机密较高,不是Web端的最终用户。
注意:要将pointClass、boundaryClass、usersBoundary 三个要素类一起发布。可以按Ctrl键选中多个图层发布。
发布成功后,添加被编辑的要素图层到当前地图。
让我们测试一下属性规则,限制编辑区域的功能。如果我们以 许工 身份登录,我们将只能在金泰大厦区域内创建要素。尝试在和平里或老国展边界内创建要素将失败,并出现不同的错误提示。
类似地,张工只能编辑老国展区域。
最后,谢工只能编辑和平里区域。
让我们在浏览器端查看在线编辑功能的边界限制属性规则依然生效。
注意:发布后的属性规则表达式发生了变化,且为只读的。所以想要修改属性规则,需要重新发布。
不过,删除和更新功能是棘手的。使用我们现在拥有的脚本,谢工可以将要素从任何边界移动到他的边界,这是因为我们只检查几何 ($feature),这是要素更新后的状态。因此,如果谢工将老国展区域的要素移动到和平里区域,当前规则会允许这个操作,但其实这个操作是不符合业务逻辑的!
为了实现这一目标,我们需要在ArcGIS Pro 2.5 / 10.8中引入一个名为$originalFeature的新Arcade全局变量。可以在此博客中阅读有关此内容的更多信息https://www.esri.com/arcgis-blog/products/arcgis-pro/data-management/originalfeature-new-attribute-rules-arcade-global/。
我们希望确保允许 谢工 将要素从其原始几何中移动,并且还允许他将要素移动到其新位置。我们将使用 Arcade 函数简化代码,让我们将所有代码放在 canEdit 中,获取用户和特征几何体,我们将基本上执行相同的代码。
最终脚本https://github.com/hussein-nasser/arcade-scripts/blob/master/restrictBoundaryEditing.js
//function that tells whether the user can edit
function canEdit(user, featureGeo) {
//get the current Boundary the feature is created/updated on.
var fsBoundary = FeatureSetByName($datastore, "restrictedits.owner.boundaryClass", ["globalId", "boundaryId"], false);
var fsIntersectedBoundaries = Intersects(fsBoundary, featureGeo )
//if no boundary error
if (Count(fsIntersectedBoundaries) == 0)
return {"errorMessage": "要素必须创建在工作区内"}
//we are interested in the first boundary
//we can enhnace the script to look for all boundaries
var boundary = First(fsIntersectedBoundaries);
var boundaryGlobalId = boundary.globalId;
//query the usersBoundary class
var usersBoundary = FeatureSetByName($datastore, "restrictedits.owner.usersBoundary");
//is the user allowed to edit this boundary?
var usercanEdit = Count(Filter(usersBoundary, "username = @user AND boundaryGuid = @boundaryGlobalId")) > 0
var boundaryId = boundary.boundaryId
//return a good error message
return {
"errorMessage": "用户 @user 未被授权编辑区域 @boundaryId",
"success": usercanEdit
}
}
//code starts here
//get the current user
var user = $feature.last_edited_user;
//get the feature geometry
var featureGeo = Geometry($feature)
//if this was an update get the original geometry (user might have moved the feature)
//$originalFeature geometry is empty when creating new features
if (!isEmpty(Geometry($originalFeature)))
{
//user is moving a feature, this is the original geometry
var originalGeo = Geometry($originalFeature)
//is she allowed to do so?
var result = canEdit(user,originalGeo);
if (result.success == false)
return {"errorMessage": result.errorMessage}
}
//is the user allowed to create/delete feature (or move a feature_
var result = canEdit(user,featureGeo);
if (result.success == false)
return {"errorMessage": result.errorMessage}
//if we reach here we are good.
return true;
//update
使用属性规则执行此操作的好处是,使用要素服务的任何客户端都将获得此行为,无论是通过 Pro、Web 编辑器还是Collector(已连接)。 您也可以编写服务器端代码(如 SOE 或 SOI)来实现类似的方案。
请注意,上面的代码仅用于演示目的,将许多用户单独分配到边界变得难以管理。因此,我们正在考虑解决此问题的更好方法,例如通过在 Arcade 中引入门户访问控制,以便我们可以以群组作为单位做记录级权限控制而不仅是对个人用户的编辑操作做记录级权限控制。