如何限制編輯范圍?如何將編輯限制在某些邊界?如何將用戶限制為僅在分配給他們的工作訂單邊界內進行編輯?是否可以限制用戶在某些邊界中進行編輯,而不能在其他邊界中進行編輯?我們經常遇到這些問題,在本博客中,我將說明如何使用屬性規則來做到這一點。
一、限制邊界區域內的編輯內容
在本例中,我們希望創建一個邊界要素類,該要素類將表示限制區域或區域。我們還將創建另一個表示數據的要素類;最后,我們將向要素類添加一個屬性規則,用于檢查正在創建或更新的要素是否在邊界內。
注意: 此示例可在裝有 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 中引入門戶訪問控制,以便我們可以以群組作為單位做記錄級權限控制而不僅是對個人用戶的編輯操作做記錄級權限控制。