In unserem Podcast diskutiert Thomas Bahn über Nutzen, Anwendungen und Erfahrungen aus den Bereichen Chatbots und Künstliche Intelligenz. Mehr erfahren

Design-Update für "Gemeinsam, privat bei Erstbenutzung"-Ordnern

von Thomas,
assono GmbH, Standort Kiel,

Manchmal wäre es wirklich nützlich, diese "Gemeinsam, privat bei Erstbenutzung"-Ordner (Shared, private on first use = SPOFU) verwenden zu können.

Soll zum Beispiel jeder Benutzer einer Notes-Anwendung die Möglichkeit haben, in einem Ordner seine Favoriten zu sammeln, und hat er keine Berechtigung, alle Dokumente der Datenbank zu verändern - es kann also nicht irgendetwas für diesen Benutzer in das Dokument selbst eingetragen werden - dann bleiben nur noch private oder eben "Gemeinsam, privat bei Erstbenutzung"-Ordner übrig.

Ein solcher Ordner ist auch schnell erstellt. Die Sache hat trotzdem einen gewichtigen Haken: Hat der Benutzer einmal auf den gemeinsamen Ordner geklickt und damit seine private Kopie erstellt, kann man die Gestaltung dieser Kopie nicht mehr zentral aktualisieren.

Eine typische Lösung für das Problem ist es, diesen Ordner zu löschen, so dass der Benutzer das nächste Mal, wenn er den Ordner benutzen will, wieder eine neue private Kopie - jetzt vom veränderten Original erstellt.

Dieser Ansatz ist aber nicht ideal:

Zum einen stellt sich die Frage, wann die Privatkopie gelöscht werden soll. Bei jedem Verlassen der Datenbank? Dann kann der Benutzer diesen Ordner praktisch gar nicht zum langfristigen Sammeln benutzen, weil er zwischen zwei Sitzungen immer geleert würde. Oder man setzt zentral irgendeine Art Signal, zum Beispiel einen bestimmten Feldwert in einem Datenbankprofil-Dokument. Dann muss man aber immer, wenn man die Gestaltung des Ordners verändert, daran denken, dieses Flag zu setzen. Besser wäre es, wenn dieses Löschen automatisch immer genau dann und nur dann passieren würde, wenn sich die Gestaltung des Originals verändert.

Zum anderen bedeutet das Löschen des Ordners natürlich auch, dass alle Dokument-Zuordnungen verloren gehen. Spätestens nach dem zweiten, dritten Mal wird kaum ein Benutzer den Favoritenordner mehr verwenden, wenn der seinen Inhalt sowieso irgendwann wieder verliert.

Aber mit ein wenig "Magie" und Fleiß lassen sich beide Probleme in den Griff bekommen...

Zuerst müssen wir die richtige Stelle finden, wo wir das Löschen implementieren wollen. Da man den Ordner nur löschen sollte, wenn er nicht gerade aktiv (also geöffnet) ist, ist das Datenbank-Script wahrscheinlich der beste Kandidat. Beim Öffnen oder beim Schließen? Ich habe mich für das Schließen der Datenbank, genauer: das QueryClose() im Datenbank-Script entschieden, weil es nicht als so performance-kritisch wahrgenommen wird wie das Öffnen einer Datenbank.

Jetzt müssen wir herausfinden, ob sich die Gestaltung des Orignials verändert hat. Dazu kann man den LastModified-Zeitpunkt des öffentlichen Ordners mit dem Created-Zeitpunkt des privaten vergleichen. Liegt LastModified zeitlich hinter Created, muss die private Kopie aktualisiert werden.
Also müssen wir auf beide Ordner irgendwie zugreifen können.

Der private Ordner ist einfach: Ein GetView(Ordnername) auf die aktuelle Datenbank und wir sind fertig. Wird Nothing zurückgegeben, wurde die Privatkopie nicht erstellt und es muss folglich auch nichts aktualisiert werden. Sonst haben wir jetzt die NotesView mit ihrer Created-Eigenschaft für den Vergleich zur Verfügung.

Der gemeinsame Ordner ist da schon schwieriger. Eine Möglichkeit, die ich gefunden habe, besteht darin, eine NotesNoteCollection mit allen Ordnern zu erstellen, diese zu durchlaufen, und beim richtigen Ordner, also dem nicht-privaten Ordner ($Flags enthält nicht "V") mit dem gegebenen Namen stehen zu bleiben. Wenn der gemeinsame Ordner nicht gelöscht oder umbenannt wurde, sollte er so auf alle Fälle gefunden werden. Performance-mäßig ist das sicherlich nicht ganz so toll, aber wenn es nicht zu viele Ordner gibt, sollte das noch tolerabel sein. Ich bin offen für andere Ideen und Ansätze...

Der Rest ist trivial: Die beiden Zeitpunkte vergleichen und gegebenenfalls den privaten Ordner mittels Remove() löschen.

Halt, da war doch noch was: Es wäre doch toll, wenn die zugeordneten Dokumente nicht verloren gehen würden.

Dazu erstelle ich einen neuen, versteckten Ordner und kopiere alle Dokumente des zu löschenden Ordners dort hinein. Danach erst lösche ich den privaten Ordner.

Hier ist der Code soweit:

Sub QueryClose(source As NotesUIDatabase, continue As Variant)

	Dim session As New NotesSession
	Dim currentDB As NotesDatabase
	Dim privateFolder As NotesView
	Dim foldersColl As NotesNoteCollection
	Dim folderNoteID As String
	Dim folderDoc As NotesDocument
	Dim i As Integer
	Dim publicFolderDoc As NotesDocument
	Dim helperFolderName As String
	Dim allEntries As NotesViewEntryCollection

	Set currentDB = session.CurrentDatabase

	' get handle to private version of the favorites folder
	Set privateFolder = currentDB.GetView("My favorites")

	' if there is no private version of the folder --> nothing to do
	If privateFolder Is Nothing Then Exit Sub

	' get handle to non-private version of the favorites folder
	Set publicFolderDoc = Nothing

	' first create NoteCollection of all folders
	Set foldersColl = currentDB.CreateNoteCollection(False)
	foldersColl.SelectFolders = True
	Call foldersColl.BuildCollection

	' then iterate through all folders
	folderNoteID = foldersColl.GetFirstNoteId
	For i = 1 To foldersColl.Count
		' get the folder's document
		Set folderDoc = currentDB.GetDocumentByID(folderNoteID)

		' if folder is "My favorites" and ...
		If folderDoc.~$TITLE(0) = "My favorites" Then
			' ... if it doesn't contain the "V" flag, that is, it is not private
			If InStr(folderDoc.~$Flags(0), "V") = 0 Then
				' then it's the public favorites folder we are looking for
				Set publicFolderDoc = folderDoc
				Exit For
			End If
		End If
		folderNoteID = foldersColl.GetNextNoteId(folderNoteID)
	Next

	' if the public folder could not be found --> nothing to do
	If publicFolderDoc Is Nothing Then Exit Sub

	' if the private version of the favorites folder is created after
	' the last modification of the public one, it is current --> nothing to do
	If publicFolderDoc.LastModified <= privateFolder.Created Then Exit Sub

	' else the private favorites folder has to be updated
	helperFolderName = "(SPOFUFolderUpdateHelper-" & session.CommonUserName & ")"
	Set allEntries = privateFolder.AllEntries

	' put all documents in this folder into a helper folder
	Call allEntries.PutAllInFolder(helperFolderName, True)

	' and remove the out-dated folder
	Call privateFolder.Remove()
End Sub

Und wie wird jetzt die neue Privatkopie erstellt? Per LotusScript geht das eigentlich nur über ein NotesUIWorkspace.OpenDatabase(). Nicht gerade ideal beim Schließen der Datenbank.

Ich warte einfach, bis der Benutzer selbst das nächste Mal den Favoritenordner öffnet und dadurch die neue Kopie erstellt wird!

Im PostOpen-Ereigbnis des Favoritenordners sehe ich dann nach, ob es einen versteckte Hilfsordner für den aktuellen Benutzer gibt. In diesem Fall kopiere ich die Dokumente daraus wieder in den privaten Favoritenordner zurück und lösche dann den Hilfsordner.

Hier der Code dazu:

Sub PostOpen(source As NotesUIView)
	
	Dim session As New NotesSession
	Dim currentDB As NotesDatabase
	Dim helperFolderName As String
	Dim updateHelperFolder As NotesView
	Dim allEntries As NotesViewEntryCollection
	Dim uiws As New NotesUIWorkspace
	
	Set currentDB = session.CurrentDatabase
	
	' if there is a FavoritesUpdateHelper folder for this user...
	helperFolderName = "(SPOFUFolderUpdateHelper-" & session.CommonUserName & ")"
	Set updateHelperFolder = currentDB.GetView(helperFolderName)
	If Not updateHelperFolder Is Nothing Then ' helper folder found
		' move all entries to current folder
		Set allEntries = updateHelperFolder.AllEntries
		Call allEntries.PutAllInFolder(source.ViewName, False)
		
		' and remove helper folder
		Call updateHelperFolder.Remove()
	End If
	
	' refresh view to show newly added documents
	Call uiws.ViewRefresh
End Sub

Das war's schon!

Fachbeitrag HCL Notes Entwicklung Für Entwickler

Sie haben Fragen zu diesem Artikel? Kontaktieren Sie uns gerne: blog@assono.de

Sie haben Interesse an diesem Thema?

Gerne bieten wir Ihnen eine individuelle Beratung oder einen Workshop an.

Kontaktieren Sie uns

Weitere interessante Artikel

Sie haben Fragen?

Wenn Sie mehr über unsere Angebote erfahren möchten, können Sie uns jederzeit kontaktieren. Gerne erstellen wir eine individuelle Demo für Sie.

assono GmbH

Standort Kiel (Zentrale)
assono GmbH
Lise-Meitner-Straße 1–7
24223 Schwentinental

Standort Hamburg
assono GmbH
Bornkampsweg 58
22761 Hamburg

Telefonnummern:
Zentrale: +49 4307 900 416
Vertrieb: +49 4307 900 402

E-Mail-Adressen:
kontakt@assono.de
bewerbung@assono.de