缘起
“删除”是几乎所有应用程序,特别是以数据为中心(Data-Centric)的应用具有的普通功能。单纯的“删除”也和新建、保存、编辑、查找等功能一样,集成在Lotus Notes客户端中,简单到不需要编程,只要和在Windows下删除文件一样按Delete键再加F9刷新即可。但是这样方便的前提是用户有权限删除这些目标文档。而在Lotus Notes特殊的数据库设计中,一个数据库的删除文档的权限是一个不可分的单元,而不像关系型数据库那样可以细分到每个表。而且,Lotus Notes中安全性被设计成基础的特性,每一段运行的程序都有一个账户身份,这个身份具备特定的权限,该程序执行的操作被限定在权限范围内。由于Lotus Notes客户端应用程序的代码都是以客户端当前所属的用户身份在客户端上运行,而绝大部分的应用程序都不可能把整个数据库的删除文档的权限赋予每一个用户,所以Lotus Notes客户端集成的删除文档功能对大部分用户都是不可用的。
常见方案
但是删除功能很多时候又是必不可少的,所以程序员就必须绕过上述限制来实现。一般采用的是“假删除”的方法,即对要删除的文档加上某个标记,使其不符合视图的选择条件,从而“消失”。比如,在一个操作中添加如下公式:
@SetField(“DeleteFlag”; 1);
然后给视图的选择公式补充相应的条件:
Select Form=”Company” & DeleteFlag!=1
与此配套地,还可以建一个视图专门包含被“删除”的文档,以及一个代理定时删除这些文档。
这个方案的好处是删除功能的代码很简单,被删除的文档还可以从类似回收站的视图查看和恢复。缺点是每个普通视图的选择公式都必须加上额外的部分以屏蔽这些文档。
另一种思路
为了克服这个缺点,笔者设计了另一个方案。真正删除文档的障碍在于用户没有权限,那我们就暂时以有权限的账户身份来运行代码,这样做的可能性就来源于代理。Lotus Notes的代理在服务器上运行时可以设置为以某个特定账户的身份运行(在代理属性信息框的安全性页里有Run on behalf of)。我们可以建一个用于删除文档的代理,以一个有相应权限的账户身份运行。在用户界面的删除操作中,调用这个代理。这样不但解决了权限问题,还可以灵活控制删除前后的逻辑。唯一的问题是,在视图里删除选定的多个文档时,如何使代理明白选择的是哪些文档。可以通过调用代理时建立一个临时文档记录要删除的文档的ID,然后将这个临时文档的ID作为参数传给代理的RunOnServer()方法。
视图操作中调用删除文档代理的代码:
Sub Click(Source As Button)
Dim s As New NotesSession
Dim db As NotesDatabase
Set db=s.CurrentDatabase
Dim ws As New NotesUIWorkspace
Dim dc As NotesDocumentCollection
Set dc=ws.CurrentView.Documents
Dim ids As New NArray(-1)
Dim doc As NotesDocument
Set doc=dc.GetFirstDocument
Do Until doc Is Nothing
‘Check if the selected document can be deleted.
If doc.Status(0)="1.1 Draft" Then
ids.Add(doc.NoteID)
End If
Set doc=dc.GetNextDocument(doc)
Loop
If ids.Count=0 Then
Msgbox "Please select drafts to delete. Submitted documents cannot be deleted."
Exit Sub
End If
Dim docPrmt As New NotesDocument(db)
docPrmt.DocIds=ids.container
Call docPrmt.Save(True, False)
Dim agent As NotesAgent
Set agent=s.CurrentDatabase.GetAgent("(agDeleteDocs)")
Call agent.RunOnServer(docPrmt.NoteID)
Msgbox ids.Count & " documents have been deleted."
Call ws.ViewRefresh()
End Sub
删除文档代理的代码:
%REM
Agent agDeleteDocs
Created Feb 29, 2012 by Starrow Pan
Description: Comments for Agent
%END REM
Option Public
Option Declare
Use "Commons"
Sub Initialize
Dim s As New NotesSession
Dim db As NotesDatabase
Set db=s.Currentdatabase
Dim agent As NotesAgent
Set agent=s.Currentagent
Dim profile As NotesDocument
Set profile=db.Getdocumentbyid(agent.Parameterdocid)
Dim ids As Variant
ids=profile.DocIds
Dim doc As NotesDocument
Dim ed As ExtDoc
ForAll id In ids
Set doc=db.Getdocumentbyid(id)
Set ed=New ExtDoc(doc)
Call ed.RemoveAll(True)
End ForAll
Call profile.Remove(True)
End Sub
Web应用程序
最后要说明的是,在用ASP、PHP、Java等各种语言开发的Web应用程序中,因为安全性是和其他所有业务逻辑一起由程序员后天开发的,而且包括操作数据库的大量代码都是以唯一的有权限的用户身份在服务器上运行的,所以“删除”操作和其他操作一样,只要程序员在其代码或专门的安全性模块里做好检查,就没有特别的问题。